commit df3dd9a705ea2e6dbb9945b1636e11ea73623d34 Author: nqthai199@gmail.com Date: Thu Sep 15 09:26:49 2022 +0700 first commit diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..d29b343 --- /dev/null +++ b/Makefile @@ -0,0 +1,129 @@ +################################################################################ +# Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +################################################################################# +#enable this flag to use optimized dsexample plugin +#it can also be exported from command line + +WITH_OPENCV?=1 + +USE_OPTIMIZED_DSEXAMPLE?=0 +CUDA_VER?=11.2 +ifeq ($(CUDA_VER),) + $(error "CUDA_VER is not set") +endif +TARGET_DEVICE = $(shell gcc -dumpmachine | cut -f1 -d -) +CXX:= g++ +NVCC:=/usr/local/cuda-$(CUDA_VER)/bin/nvcc + +ifeq ($(USE_OPTIMIZED_DSEXAMPLE),1) + SRCS:= gstdsexample_optimized.cpp +else + SRCS:= gstdsexample.cpp + SRCS+= ./src/CharacterDetection.cpp + SRCS+= ./src/CropLicensePlate.cpp + SRCS+= ./src/GetPlateColor.cpp + SRCS+= ./src/LicensePlateRecognition.cpp + SRCS+= ./src/LPRprocessor.cpp + SRCS+= ./src/config.cpp + SRCS+= ./src/CropLP.cpp + SRCS+= ./src/YOLOv5/preprocess.cu + SRCS+= ./src/YOLOv5/yololayer.cu + SRCS+= ./src/YOLOv5/DetectorCOCO.cpp + + +endif + +INCS:= $(wildcard *.h) +INCS+= $(wildcard ./include/*.h) +INCS+= $(wildcard ./include/*.hpp) +INCS+= $(wildcard ./include/YOLOv5/*.h) +INCS+= $(wildcard ./include/YOLOv5/*.hpp) + +LIB:=libnvdsgst_dsexample.so + +NVDS_VERSION:=6.0 + +DEP:=dsexample_lib/libdsexample.a +DEP_FILES:=$(wildcard dsexample_lib/dsexample_lib.* ) +DEP_FILES-=$(DEP) + +CFLAGS+= -fPIC -DDS_VERSION=\"6.0\" \ + -I /usr/local/cuda-$(CUDA_VER)/include \ + -I ../../includes \ + -I ./lib_ncnn/ncnn \ + -I ./include \ + -I ./include/YOLOv5 + +CFLAGS_NVCC:=$(shell pkg-config --cflags --libs opencv4 ) +CFLAGS_NVCC+=-I ./include -I ./include/YOLOv5 + +GST_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/gst-plugins/ +LIB_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/ + +LIBS := -shared -Wl,-no-undefined \ + -L dsexample_lib -ldsexample \ + -L/usr/local/cuda-$(CUDA_VER)/lib64/ -lcudart -ldl \ + -lnppc -lnppig -lnpps -lnppicc -lnppidei \ + -L$(LIB_INSTALL_DIR) -lnvdsgst_helper -lnvdsgst_meta -lnvds_meta -lnvbufsurface -lnvbufsurftransform \ + -Wl,-rpath,$(LIB_INSTALL_DIR) \ + -L lib_ncnn -lncnn -fopenmp\ + -lnvinfer -lpthread \ + # -lnvinfer_plugin -lnvparsers \ + + +OBJS:= $(SRCS:.cpp=.o) +OBJS:= $(OBJS:.cu=.o) + +PKGS:= gstreamer-1.0 gstreamer-base-1.0 gstreamer-video-1.0 + +ifeq ($(WITH_OPENCV),1) +CFLAGS+= -DWITH_OPENCV +ifeq ($(TARGET_DEVICE),aarch64) + PKGS+= opencv4 +else + PKGS+= opencv +endif +endif + +CFLAGS+=$(shell pkg-config --cflags $(PKGS)) +LIBS+=$(shell pkg-config --libs $(PKGS)) + +all: $(LIB) + +%.o: %.cpp $(INCS) Makefile + @echo $(CFLAGS) + $(CXX) -c -o $@ $(CFLAGS) $< + +%.o: %.cu $(INCS) Makefile + $(NVCC) -c -o $@ $(CFLAGS_NVCC) --compiler-options '-fPIC' $< + +$(LIB): $(OBJS) $(DEP) Makefile + @echo $(CFLAGS) + $(CXX) -o $@ $(OBJS) $(LIBS) + +$(DEP): $(DEP_FILES) + $(MAKE) -C dsexample_lib/ + +install: $(LIB) + cp -rv $(LIB) $(GST_INSTALL_DIR) + +clean: + rm -rf $(OBJS) $(LIB) diff --git a/README b/README new file mode 100755 index 0000000..ccc62a1 --- /dev/null +++ b/README @@ -0,0 +1,51 @@ +################################################################################ +# Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA Corporation and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA Corporation is strictly prohibited. +# +################################################################################ + +Refer to the DeepStream SDK documentation for a description of the plugin. +-------------------------------------------------------------------------------- +Pre-requisites: +- GStreamer-1.0 Development package +- GStreamer-1.0 Base Plugins Development package +- OpenCV Development package + +Install using: + sudo apt-get install libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev \ + libopencv-dev + +-------------------------------------------------------------------------------- +Compiling and installing the plugin: +Export or set in Makefile the appropriate cuda version using CUDA_VER +Run make and sudo make install + +NOTE: +1. To compile the sources, run make with "sudo" or root permission. +2. This plugin contains additional optimized sample which supports batch processing +of buffers. Refer to the Makefile for using optimized sample. +3. OpenCV has been deprecated by default, so blur-objects will not work. + To enable OpenCV in dsexample, set `WITH_OPENCV=1` in the plugin Makefile + (/opt/nvidia/deepstream/deepstream/sources/gst-plugins/gst-dsexample/Makefile) + and follow compilation and installation instructions present in this README. + +-------------------------------------------------------------------------------- +Corresponding config file changes (Add the following section). GPU ID might need +modification based on the GPU configuration: +[ds-example] +enable=1 +processing-width=640 +processing-height=480 +full-frame=0 +#batch-size for batch supported optimized plugin +batch-size=1 +unique-id=15 +gpu-id=0 +blur-objects=0 +# Supported memory types for blur-objects are 1 and 3 +nvbuf-memory-type=3 diff --git a/data/character_detection/character-detection-nano-416-16032022.bin b/data/character_detection/character-detection-nano-416-16032022.bin new file mode 100755 index 0000000..12fb7b2 Binary files /dev/null and b/data/character_detection/character-detection-nano-416-16032022.bin differ diff --git a/data/character_detection/character-detection-nano-416-16032022.param b/data/character_detection/character-detection-nano-416-16032022.param new file mode 100755 index 0000000..2582d0b --- /dev/null +++ b/data/character_detection/character-detection-nano-416-16032022.param @@ -0,0 +1,282 @@ +7767517 +280 310 +Input images 0 1 images +YoloV5Focus focus 1 1 images 683 +Convolution Conv_41 1 1 683 1177 0=16 1=3 4=1 5=1 6=1728 +Swish Mul_43 1 1 1177 687 +ConvolutionDepthWise Conv_44 1 1 687 1180 0=16 1=3 3=2 4=1 5=1 6=144 7=16 +Swish Mul_46 1 1 1180 691 +Convolution Conv_47 1 1 691 1183 0=32 1=1 5=1 6=512 +Swish Mul_49 1 1 1183 695 +Split splitncnn_0 1 2 695 695_splitncnn_0 695_splitncnn_1 +Convolution Conv_50 1 1 695_splitncnn_1 1186 0=16 1=1 5=1 6=512 +Swish Mul_52 1 1 1186 699 +Split splitncnn_1 1 2 699 699_splitncnn_0 699_splitncnn_1 +Convolution Conv_53 1 1 695_splitncnn_0 1189 0=16 1=1 5=1 6=512 +Swish Mul_55 1 1 1189 703 +Convolution Conv_56 1 1 699_splitncnn_1 1192 0=16 1=1 5=1 6=256 +Swish Mul_58 1 1 1192 707 +ConvolutionDepthWise Conv_59 1 1 707 1195 0=16 1=3 4=1 5=1 6=144 7=16 +Swish Mul_61 1 1 1195 711 +Convolution Conv_62 1 1 711 1198 0=16 1=1 5=1 6=256 +Swish Mul_64 1 1 1198 715 +BinaryOp Add_65 2 1 715 699_splitncnn_0 716 +Concat Concat_66 2 1 716 703 717 +Convolution Conv_67 1 1 717 1201 0=32 1=1 5=1 6=1024 +Swish Mul_69 1 1 1201 721 +ConvolutionDepthWise Conv_70 1 1 721 1204 0=32 1=3 3=2 4=1 5=1 6=288 7=32 +Swish Mul_72 1 1 1204 725 +Convolution Conv_73 1 1 725 1207 0=64 1=1 5=1 6=2048 +Swish Mul_75 1 1 1207 729 +Split splitncnn_2 1 2 729 729_splitncnn_0 729_splitncnn_1 +Convolution Conv_76 1 1 729_splitncnn_1 1210 0=32 1=1 5=1 6=2048 +Swish Mul_78 1 1 1210 733 +Split splitncnn_3 1 2 733 733_splitncnn_0 733_splitncnn_1 +Convolution Conv_79 1 1 729_splitncnn_0 1213 0=32 1=1 5=1 6=2048 +Swish Mul_81 1 1 1213 737 +Convolution Conv_82 1 1 733_splitncnn_1 1216 0=32 1=1 5=1 6=1024 +Swish Mul_84 1 1 1216 741 +ConvolutionDepthWise Conv_85 1 1 741 1219 0=32 1=3 4=1 5=1 6=288 7=32 +Swish Mul_87 1 1 1219 745 +Convolution Conv_88 1 1 745 1222 0=32 1=1 5=1 6=1024 +Swish Mul_90 1 1 1222 749 +BinaryOp Add_91 2 1 749 733_splitncnn_0 750 +Split splitncnn_4 1 2 750 750_splitncnn_0 750_splitncnn_1 +Convolution Conv_92 1 1 750_splitncnn_1 1225 0=32 1=1 5=1 6=1024 +Swish Mul_94 1 1 1225 754 +ConvolutionDepthWise Conv_95 1 1 754 1228 0=32 1=3 4=1 5=1 6=288 7=32 +Swish Mul_97 1 1 1228 758 +Convolution Conv_98 1 1 758 1231 0=32 1=1 5=1 6=1024 +Swish Mul_100 1 1 1231 762 +BinaryOp Add_101 2 1 762 750_splitncnn_0 763 +Split splitncnn_5 1 2 763 763_splitncnn_0 763_splitncnn_1 +Convolution Conv_102 1 1 763_splitncnn_1 1234 0=32 1=1 5=1 6=1024 +Swish Mul_104 1 1 1234 767 +ConvolutionDepthWise Conv_105 1 1 767 1237 0=32 1=3 4=1 5=1 6=288 7=32 +Swish Mul_107 1 1 1237 771 +Convolution Conv_108 1 1 771 1240 0=32 1=1 5=1 6=1024 +Swish Mul_110 1 1 1240 775 +BinaryOp Add_111 2 1 775 763_splitncnn_0 776 +Concat Concat_112 2 1 776 737 777 +Convolution Conv_113 1 1 777 1243 0=64 1=1 5=1 6=4096 +Swish Mul_115 1 1 1243 781 +Split splitncnn_6 1 2 781 781_splitncnn_0 781_splitncnn_1 +ConvolutionDepthWise Conv_116 1 1 781_splitncnn_1 1246 0=64 1=3 3=2 4=1 5=1 6=576 7=64 +Swish Mul_118 1 1 1246 785 +Convolution Conv_119 1 1 785 1249 0=128 1=1 5=1 6=8192 +Swish Mul_121 1 1 1249 789 +Split splitncnn_7 1 2 789 789_splitncnn_0 789_splitncnn_1 +Convolution Conv_122 1 1 789_splitncnn_1 1252 0=64 1=1 5=1 6=8192 +Swish Mul_124 1 1 1252 793 +Split splitncnn_8 1 2 793 793_splitncnn_0 793_splitncnn_1 +Convolution Conv_125 1 1 789_splitncnn_0 1255 0=64 1=1 5=1 6=8192 +Swish Mul_127 1 1 1255 797 +Convolution Conv_128 1 1 793_splitncnn_1 1258 0=64 1=1 5=1 6=4096 +Swish Mul_130 1 1 1258 801 +ConvolutionDepthWise Conv_131 1 1 801 1261 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_133 1 1 1261 805 +Convolution Conv_134 1 1 805 1264 0=64 1=1 5=1 6=4096 +Swish Mul_136 1 1 1264 809 +BinaryOp Add_137 2 1 809 793_splitncnn_0 810 +Split splitncnn_9 1 2 810 810_splitncnn_0 810_splitncnn_1 +Convolution Conv_138 1 1 810_splitncnn_1 1267 0=64 1=1 5=1 6=4096 +Swish Mul_140 1 1 1267 814 +ConvolutionDepthWise Conv_141 1 1 814 1270 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_143 1 1 1270 818 +Convolution Conv_144 1 1 818 1273 0=64 1=1 5=1 6=4096 +Swish Mul_146 1 1 1273 822 +BinaryOp Add_147 2 1 822 810_splitncnn_0 823 +Split splitncnn_10 1 2 823 823_splitncnn_0 823_splitncnn_1 +Convolution Conv_148 1 1 823_splitncnn_1 1276 0=64 1=1 5=1 6=4096 +Swish Mul_150 1 1 1276 827 +ConvolutionDepthWise Conv_151 1 1 827 1279 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_153 1 1 1279 831 +Convolution Conv_154 1 1 831 1282 0=64 1=1 5=1 6=4096 +Swish Mul_156 1 1 1282 835 +BinaryOp Add_157 2 1 835 823_splitncnn_0 836 +Concat Concat_158 2 1 836 797 837 +Convolution Conv_159 1 1 837 1285 0=128 1=1 5=1 6=16384 +Swish Mul_161 1 1 1285 841 +Split splitncnn_11 1 2 841 841_splitncnn_0 841_splitncnn_1 +ConvolutionDepthWise Conv_162 1 1 841_splitncnn_1 1288 0=128 1=3 3=2 4=1 5=1 6=1152 7=128 +Swish Mul_164 1 1 1288 845 +Convolution Conv_165 1 1 845 1291 0=256 1=1 5=1 6=32768 +Swish Mul_167 1 1 1291 849 +Convolution Conv_168 1 1 849 1294 0=128 1=1 5=1 6=32768 +Swish Mul_170 1 1 1294 853 +Split splitncnn_12 1 4 853 853_splitncnn_0 853_splitncnn_1 853_splitncnn_2 853_splitncnn_3 +Pooling MaxPool_171 1 1 853_splitncnn_3 854 1=5 3=2 5=1 +Pooling MaxPool_172 1 1 853_splitncnn_2 855 1=9 3=4 5=1 +Pooling MaxPool_173 1 1 853_splitncnn_1 856 1=13 3=6 5=1 +Concat Concat_174 4 1 853_splitncnn_0 854 855 856 857 +Convolution Conv_175 1 1 857 1297 0=256 1=1 5=1 6=131072 +Swish Mul_177 1 1 1297 861 +Split splitncnn_13 1 2 861 861_splitncnn_0 861_splitncnn_1 +Convolution Conv_178 1 1 861_splitncnn_1 1300 0=128 1=1 5=1 6=32768 +Swish Mul_180 1 1 1300 865 +Convolution Conv_181 1 1 861_splitncnn_0 1303 0=128 1=1 5=1 6=32768 +Swish Mul_183 1 1 1303 869 +Convolution Conv_184 1 1 865 1306 0=128 1=1 5=1 6=16384 +Swish Mul_186 1 1 1306 873 +ConvolutionDepthWise Conv_187 1 1 873 1309 0=128 1=3 4=1 5=1 6=1152 7=128 +Swish Mul_189 1 1 1309 877 +Convolution Conv_190 1 1 877 1312 0=128 1=1 5=1 6=16384 +Swish Mul_192 1 1 1312 881 +Concat Concat_193 2 1 881 869 882 +Convolution Conv_194 1 1 882 1315 0=256 1=1 5=1 6=65536 +Swish Mul_196 1 1 1315 886 +Convolution Conv_197 1 1 886 1318 0=128 1=1 5=1 6=32768 +Swish Mul_199 1 1 1318 890 +Split splitncnn_14 1 2 890 890_splitncnn_0 890_splitncnn_1 +Interp Resize_201 1 1 890_splitncnn_1 895 0=1 1=2.000000e+00 2=2.000000e+00 +Concat Concat_202 2 1 895 841_splitncnn_0 896 +Split splitncnn_15 1 2 896 896_splitncnn_0 896_splitncnn_1 +Convolution Conv_203 1 1 896_splitncnn_1 1321 0=64 1=1 5=1 6=16384 +Swish Mul_205 1 1 1321 900 +Convolution Conv_206 1 1 896_splitncnn_0 1324 0=64 1=1 5=1 6=16384 +Swish Mul_208 1 1 1324 904 +Convolution Conv_209 1 1 900 1327 0=64 1=1 5=1 6=4096 +Swish Mul_211 1 1 1327 908 +ConvolutionDepthWise Conv_212 1 1 908 1330 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_214 1 1 1330 912 +Convolution Conv_215 1 1 912 1333 0=64 1=1 5=1 6=4096 +Swish Mul_217 1 1 1333 916 +Concat Concat_218 2 1 916 904 917 +Convolution Conv_219 1 1 917 1336 0=128 1=1 5=1 6=16384 +Swish Mul_221 1 1 1336 921 +Convolution Conv_222 1 1 921 1339 0=64 1=1 5=1 6=8192 +Swish Mul_224 1 1 1339 925 +Split splitncnn_16 1 2 925 925_splitncnn_0 925_splitncnn_1 +Interp Resize_226 1 1 925_splitncnn_1 930 0=1 1=2.000000e+00 2=2.000000e+00 +Concat Concat_227 2 1 930 781_splitncnn_0 931 +Split splitncnn_17 1 2 931 931_splitncnn_0 931_splitncnn_1 +Convolution Conv_228 1 1 931_splitncnn_1 1342 0=32 1=1 5=1 6=4096 +Swish Mul_230 1 1 1342 935 +Convolution Conv_231 1 1 931_splitncnn_0 1345 0=32 1=1 5=1 6=4096 +Swish Mul_233 1 1 1345 939 +Convolution Conv_234 1 1 935 1348 0=32 1=1 5=1 6=1024 +Swish Mul_236 1 1 1348 943 +ConvolutionDepthWise Conv_237 1 1 943 1351 0=32 1=3 4=1 5=1 6=288 7=32 +Swish Mul_239 1 1 1351 947 +Convolution Conv_240 1 1 947 1354 0=32 1=1 5=1 6=1024 +Swish Mul_242 1 1 1354 951 +Concat Concat_243 2 1 951 939 952 +Convolution Conv_244 1 1 952 1357 0=64 1=1 5=1 6=4096 +Swish Mul_246 1 1 1357 956 +Split splitncnn_18 1 2 956 956_splitncnn_0 956_splitncnn_1 +ConvolutionDepthWise Conv_247 1 1 956_splitncnn_1 1360 0=64 1=3 3=2 4=1 5=1 6=576 7=64 +Swish Mul_249 1 1 1360 960 +Convolution Conv_250 1 1 960 1363 0=64 1=1 5=1 6=4096 +Swish Mul_252 1 1 1363 964 +Concat Concat_253 2 1 964 925_splitncnn_0 965 +Split splitncnn_19 1 2 965 965_splitncnn_0 965_splitncnn_1 +Convolution Conv_254 1 1 965_splitncnn_1 1366 0=64 1=1 5=1 6=8192 +Swish Mul_256 1 1 1366 969 +Convolution Conv_257 1 1 965_splitncnn_0 1369 0=64 1=1 5=1 6=8192 +Swish Mul_259 1 1 1369 973 +Convolution Conv_260 1 1 969 1372 0=64 1=1 5=1 6=4096 +Swish Mul_262 1 1 1372 977 +ConvolutionDepthWise Conv_263 1 1 977 1375 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_265 1 1 1375 981 +Convolution Conv_266 1 1 981 1378 0=64 1=1 5=1 6=4096 +Swish Mul_268 1 1 1378 985 +Concat Concat_269 2 1 985 973 986 +Convolution Conv_270 1 1 986 1381 0=128 1=1 5=1 6=16384 +Swish Mul_272 1 1 1381 990 +Split splitncnn_20 1 2 990 990_splitncnn_0 990_splitncnn_1 +ConvolutionDepthWise Conv_273 1 1 990_splitncnn_1 1384 0=128 1=3 3=2 4=1 5=1 6=1152 7=128 +Swish Mul_275 1 1 1384 994 +Convolution Conv_276 1 1 994 1387 0=128 1=1 5=1 6=16384 +Swish Mul_278 1 1 1387 998 +Concat Concat_279 2 1 998 890_splitncnn_0 999 +Split splitncnn_21 1 2 999 999_splitncnn_0 999_splitncnn_1 +Convolution Conv_280 1 1 999_splitncnn_1 1390 0=128 1=1 5=1 6=32768 +Swish Mul_282 1 1 1390 1003 +Convolution Conv_283 1 1 999_splitncnn_0 1393 0=128 1=1 5=1 6=32768 +Swish Mul_285 1 1 1393 1007 +Convolution Conv_286 1 1 1003 1396 0=128 1=1 5=1 6=16384 +Swish Mul_288 1 1 1396 1011 +ConvolutionDepthWise Conv_289 1 1 1011 1399 0=128 1=3 4=1 5=1 6=1152 7=128 +Swish Mul_291 1 1 1399 1015 +Convolution Conv_292 1 1 1015 1402 0=128 1=1 5=1 6=16384 +Swish Mul_294 1 1 1402 1019 +Concat Concat_295 2 1 1019 1007 1020 +Convolution Conv_296 1 1 1020 1405 0=256 1=1 5=1 6=65536 +Swish Mul_298 1 1 1405 1024 +Convolution Conv_299 1 1 956_splitncnn_0 1408 0=64 1=1 5=1 6=4096 +Swish Mul_301 1 1 1408 1028 +Split splitncnn_22 1 2 1028 1028_splitncnn_0 1028_splitncnn_1 +ConvolutionDepthWise Conv_302 1 1 1028_splitncnn_1 1411 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_304 1 1 1411 1032 +Convolution Conv_305 1 1 1032 1414 0=64 1=1 5=1 6=4096 +Swish Mul_307 1 1 1414 1036 +ConvolutionDepthWise Conv_308 1 1 1036 1417 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_310 1 1 1417 1040 +Convolution Conv_311 1 1 1040 1420 0=64 1=1 5=1 6=4096 +Swish Mul_313 1 1 1420 1044 +Convolution Conv_314 1 1 1044 1065 0=34 1=1 5=1 6=2176 9=4 +ConvolutionDepthWise Conv_315 1 1 1028_splitncnn_0 1423 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_317 1 1 1423 1049 +Convolution Conv_318 1 1 1049 1426 0=64 1=1 5=1 6=4096 +Swish Mul_320 1 1 1426 1053 +ConvolutionDepthWise Conv_321 1 1 1053 1429 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_323 1 1 1429 1057 +Convolution Conv_324 1 1 1057 1432 0=64 1=1 5=1 6=4096 +Swish Mul_326 1 1 1432 1061 +Split splitncnn_23 1 2 1061 1061_splitncnn_0 1061_splitncnn_1 +Convolution Conv_327 1 1 1061_splitncnn_1 1062 0=4 1=1 5=1 6=256 +Convolution Conv_328 1 1 1061_splitncnn_0 1064 0=1 1=1 5=1 6=64 9=4 +Concat Concat_331 3 1 1062 1064 1065 1066 +Convolution Conv_332 1 1 990_splitncnn_0 1435 0=64 1=1 5=1 6=8192 +Swish Mul_334 1 1 1435 1070 +Split splitncnn_24 1 2 1070 1070_splitncnn_0 1070_splitncnn_1 +ConvolutionDepthWise Conv_335 1 1 1070_splitncnn_1 1438 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_337 1 1 1438 1074 +Convolution Conv_338 1 1 1074 1441 0=64 1=1 5=1 6=4096 +Swish Mul_340 1 1 1441 1078 +ConvolutionDepthWise Conv_341 1 1 1078 1444 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_343 1 1 1444 1082 +Convolution Conv_344 1 1 1082 1447 0=64 1=1 5=1 6=4096 +Swish Mul_346 1 1 1447 1086 +Convolution Conv_347 1 1 1086 1107 0=34 1=1 5=1 6=2176 9=4 +ConvolutionDepthWise Conv_348 1 1 1070_splitncnn_0 1450 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_350 1 1 1450 1091 +Convolution Conv_351 1 1 1091 1453 0=64 1=1 5=1 6=4096 +Swish Mul_353 1 1 1453 1095 +ConvolutionDepthWise Conv_354 1 1 1095 1456 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_356 1 1 1456 1099 +Convolution Conv_357 1 1 1099 1459 0=64 1=1 5=1 6=4096 +Swish Mul_359 1 1 1459 1103 +Split splitncnn_25 1 2 1103 1103_splitncnn_0 1103_splitncnn_1 +Convolution Conv_360 1 1 1103_splitncnn_1 1104 0=4 1=1 5=1 6=256 +Convolution Conv_361 1 1 1103_splitncnn_0 1106 0=1 1=1 5=1 6=64 9=4 +Concat Concat_364 3 1 1104 1106 1107 1108 +Convolution Conv_365 1 1 1024 1462 0=64 1=1 5=1 6=16384 +Swish Mul_367 1 1 1462 1112 +Split splitncnn_26 1 2 1112 1112_splitncnn_0 1112_splitncnn_1 +ConvolutionDepthWise Conv_368 1 1 1112_splitncnn_1 1465 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_370 1 1 1465 1116 +Convolution Conv_371 1 1 1116 1468 0=64 1=1 5=1 6=4096 +Swish Mul_373 1 1 1468 1120 +ConvolutionDepthWise Conv_374 1 1 1120 1471 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_376 1 1 1471 1124 +Convolution Conv_377 1 1 1124 1474 0=64 1=1 5=1 6=4096 +Swish Mul_379 1 1 1474 1128 +Convolution Conv_380 1 1 1128 1149 0=34 1=1 5=1 6=2176 9=4 +ConvolutionDepthWise Conv_381 1 1 1112_splitncnn_0 1477 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_383 1 1 1477 1133 +Convolution Conv_384 1 1 1133 1480 0=64 1=1 5=1 6=4096 +Swish Mul_386 1 1 1480 1137 +ConvolutionDepthWise Conv_387 1 1 1137 1483 0=64 1=3 4=1 5=1 6=576 7=64 +Swish Mul_389 1 1 1483 1141 +Convolution Conv_390 1 1 1141 1486 0=64 1=1 5=1 6=4096 +Swish Mul_392 1 1 1486 1145 +Split splitncnn_27 1 2 1145 1145_splitncnn_0 1145_splitncnn_1 +Convolution Conv_393 1 1 1145_splitncnn_1 1146 0=4 1=1 5=1 6=256 +Convolution Conv_394 1 1 1145_splitncnn_0 1148 0=1 1=1 5=1 6=64 9=4 +Concat Concat_397 3 1 1146 1148 1149 1150 +Reshape Reshape_405 1 1 1066 1158 0=-1 1=39 +Reshape Reshape_413 1 1 1108 1166 0=-1 1=39 +Reshape Reshape_421 1 1 1150 1174 0=-1 1=39 +Concat Concat_422 3 1 1158 1166 1174 1175 0=1 +Permute Transpose_423 1 1 1175 output 0=1 diff --git a/data/config.json b/data/config.json new file mode 100755 index 0000000..a260dad --- /dev/null +++ b/data/config.json @@ -0,0 +1,96 @@ +{ + "mode": { + "gpuEnable" : 1, + "gpu_id" : 0 + }, + "num_threads" : 1, + "port" : 8080, + "models" : { + "detect4pointsquare" : "/opt/nvidia/deepstream/deepstream-6.0/sources/gst-plugins/gst-dsexample-OCR/data/wpod/detect_plate", + "character_detection_416_YOLOX": "/opt/nvidia/deepstream/deepstream-6.0/sources/gst-plugins/gst-dsexample-OCR/data/character_detection/character-detection-nano-416-16032022" + }, + "threshold": { + "ocr": 0.3, + "nms": 0.3, + "detect": 0.7, + "detect_size": 144.0, + "min_width": 15, + "wh_ratio": 2.0 + }, + "using_filter_ocr": true, + "save_path": "../data", + "save_img": true, + "save_fail": true, + "color_classify":{ + "crop_plate":{ + "long":[[10,70], [10,230]], + "square":[[10,150], [10,230]] + }, + "red":{ + "low":[[0, 70, 80], [10, 255, 255]], + "up":[[150, 70, 80], [180, 255, 255]] + }, + "blue_min_thres":0.08, + "blue":[[100, 90, 110], [125, 255, 255]], + "blue_dark":[[100, 70, 80], [130, 100, 120]], + "yellow":[[10, 100, 100], [60, 255, 255]], + "gray": [[0, 0, 70], [180, 80, 255]], + "white":[[0, 0, 0], [10, 120, 255]], + "black": [[0, 0, 0], [180,255,55]], + "black1": [[100, 100, 38], [130,255,50]] + }, + "prob_remove_trash": 0.9, + "rules": { + "head": { + "enable": false, + "rule": { + "C": "0", "D": "0", + "F": "", "G": "6", "H": "", "I": "1", "J": "1", + "K": "", "L": "4", "M": "", "N": "", + "P": "", "Q": "0", "R": "", "S": "5", "T": "", + "U": "0", "V": "", "W": "", + "X": "", "Y": "", "Z": "2" + } + }, + "mid": { + "enable": false, + "rule": { + "W": "N" + } + }, + "tail": { + "enable": false, + "rule": { + "A": "4", "B": "8", "C": "0", "D": "0", "E": "", + "F": "", "G": "6", "H": "", "I": "1", "J": "1", + "K": "", "L": "4", "M": "", "N": "", "O": "0", + "P": "", "Q": "0", "R": "", "S": "5", "T": "", + "U": "0", "V": "", "W": "", + "X": "", "Y": "", "Z": "2" + } + } + }, + "save_logs_api": { + "enable": false, + "push_log": { + "url": "http://localhost:4004", + "api_log":"/logs", + "method": "post" + } + }, + "os": "windows", + "timeout": 5, + "open_door": { + "enable": 2, + "url": "http://192.168.0.11:2001/connect", + "api_open_door":"/connect", + "in": { + "doorId": "1", + "c3-ip": "192.168.1.204" + }, + "out": { + "doorId": "2", + "c3-ip": "192.168.1.206" + } + } +} diff --git a/data/wpod/detect_plate.bin b/data/wpod/detect_plate.bin new file mode 100755 index 0000000..186f1b1 Binary files /dev/null and b/data/wpod/detect_plate.bin differ diff --git a/data/wpod/detect_plate.param b/data/wpod/detect_plate.param new file mode 100755 index 0000000..d5a5cf5 --- /dev/null +++ b/data/wpod/detect_plate.param @@ -0,0 +1,102 @@ +7767517 +100 110 +Input input 0 1 input_blob 0=-1 1=-1 2=3 +Convolution conv2d_1 1 1 input_blob conv2d_1_blob 0=16 1=3 2=1 3=1 4=-233 5=1 6=432 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_1 1 1 conv2d_1_blob batch_normalization_1_blob 0=16 1=1.000000e-03 +ReLU activation_1 1 1 batch_normalization_1_blob activation_1_blob 0=0.000000e+00 1=0 +Convolution conv2d_2 1 1 activation_1_blob conv2d_2_blob 0=16 1=3 2=1 3=1 4=-233 5=1 6=2304 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_2 1 1 conv2d_2_blob batch_normalization_2_blob 0=16 1=1.000000e-03 +ReLU activation_2 1 1 batch_normalization_2_blob activation_2_blob 0=0.000000e+00 1=0 +Pooling max_pooling2d_1 1 1 activation_2_blob max_pooling2d_1_blob 0=0 1=2 11=2 2=2 12=2 3=0 4=0 5=1 +Convolution conv2d_3 1 1 max_pooling2d_1_blob conv2d_3_blob 0=32 1=3 2=1 3=1 4=-233 5=1 6=4608 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_3 1 1 conv2d_3_blob batch_normalization_3_blob 0=32 1=1.000000e-03 +ReLU activation_3 1 1 batch_normalization_3_blob activation_3_blob 0=0.000000e+00 1=0 +Split activation_3_Split 1 2 activation_3_blob activation_3_Split_blob_idx_0 activation_3_Split_blob_idx_1 +Convolution conv2d_4 1 1 activation_3_Split_blob_idx_0 conv2d_4_blob 0=32 1=3 2=1 3=1 4=-233 5=1 6=9216 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_4 1 1 conv2d_4_blob batch_normalization_4_blob 0=32 1=1.000000e-03 +ReLU activation_4 1 1 batch_normalization_4_blob activation_4_blob 0=0.000000e+00 1=0 +Convolution conv2d_5 1 1 activation_4_blob conv2d_5_blob 0=32 1=3 2=1 3=1 4=-233 5=1 6=9216 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_5 1 1 conv2d_5_blob batch_normalization_5_blob 0=32 1=1.000000e-03 +BinaryOp add_1 2 1 batch_normalization_5_blob activation_3_Split_blob_idx_1 add_1_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_5 1 1 add_1_blob activation_5_blob 0=0.000000e+00 1=0 +Pooling max_pooling2d_2 1 1 activation_5_blob max_pooling2d_2_blob 0=0 1=2 11=2 2=2 12=2 3=0 4=0 5=1 +Convolution conv2d_6 1 1 max_pooling2d_2_blob conv2d_6_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=18432 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_6 1 1 conv2d_6_blob batch_normalization_6_blob 0=64 1=1.000000e-03 +ReLU activation_6 1 1 batch_normalization_6_blob activation_6_blob 0=0.000000e+00 1=0 +Split activation_6_Split 1 2 activation_6_blob activation_6_Split_blob_idx_0 activation_6_Split_blob_idx_1 +Convolution conv2d_7 1 1 activation_6_Split_blob_idx_0 conv2d_7_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_7 1 1 conv2d_7_blob batch_normalization_7_blob 0=64 1=1.000000e-03 +ReLU activation_7 1 1 batch_normalization_7_blob activation_7_blob 0=0.000000e+00 1=0 +Convolution conv2d_8 1 1 activation_7_blob conv2d_8_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_8 1 1 conv2d_8_blob batch_normalization_8_blob 0=64 1=1.000000e-03 +BinaryOp add_2 2 1 batch_normalization_8_blob activation_6_Split_blob_idx_1 add_2_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_8 1 1 add_2_blob activation_8_blob 0=0.000000e+00 1=0 +Split activation_8_Split 1 2 activation_8_blob activation_8_Split_blob_idx_0 activation_8_Split_blob_idx_1 +Convolution conv2d_9 1 1 activation_8_Split_blob_idx_0 conv2d_9_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_9 1 1 conv2d_9_blob batch_normalization_9_blob 0=64 1=1.000000e-03 +ReLU activation_9 1 1 batch_normalization_9_blob activation_9_blob 0=0.000000e+00 1=0 +Convolution conv2d_10 1 1 activation_9_blob conv2d_10_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_10 1 1 conv2d_10_blob batch_normalization_10_blob 0=64 1=1.000000e-03 +BinaryOp add_3 2 1 batch_normalization_10_blob activation_8_Split_blob_idx_1 add_3_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_10 1 1 add_3_blob activation_10_blob 0=0.000000e+00 1=0 +Pooling max_pooling2d_3 1 1 activation_10_blob max_pooling2d_3_blob 0=0 1=2 11=2 2=2 12=2 3=0 4=0 5=1 +Convolution conv2d_11 1 1 max_pooling2d_3_blob conv2d_11_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_11 1 1 conv2d_11_blob batch_normalization_11_blob 0=64 1=1.000000e-03 +ReLU activation_11 1 1 batch_normalization_11_blob activation_11_blob 0=0.000000e+00 1=0 +Split activation_11_Split 1 2 activation_11_blob activation_11_Split_blob_idx_0 activation_11_Split_blob_idx_1 +Convolution conv2d_12 1 1 activation_11_Split_blob_idx_0 conv2d_12_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_12 1 1 conv2d_12_blob batch_normalization_12_blob 0=64 1=1.000000e-03 +ReLU activation_12 1 1 batch_normalization_12_blob activation_12_blob 0=0.000000e+00 1=0 +Convolution conv2d_13 1 1 activation_12_blob conv2d_13_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_13 1 1 conv2d_13_blob batch_normalization_13_blob 0=64 1=1.000000e-03 +BinaryOp add_4 2 1 batch_normalization_13_blob activation_11_Split_blob_idx_1 add_4_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_13 1 1 add_4_blob activation_13_blob 0=0.000000e+00 1=0 +Split activation_13_Split 1 2 activation_13_blob activation_13_Split_blob_idx_0 activation_13_Split_blob_idx_1 +Convolution conv2d_14 1 1 activation_13_Split_blob_idx_0 conv2d_14_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_14 1 1 conv2d_14_blob batch_normalization_14_blob 0=64 1=1.000000e-03 +ReLU activation_14 1 1 batch_normalization_14_blob activation_14_blob 0=0.000000e+00 1=0 +Convolution conv2d_15 1 1 activation_14_blob conv2d_15_blob 0=64 1=3 2=1 3=1 4=-233 5=1 6=36864 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_15 1 1 conv2d_15_blob batch_normalization_15_blob 0=64 1=1.000000e-03 +BinaryOp add_5 2 1 batch_normalization_15_blob activation_13_Split_blob_idx_1 add_5_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_15 1 1 add_5_blob activation_15_blob 0=0.000000e+00 1=0 +Pooling max_pooling2d_4 1 1 activation_15_blob max_pooling2d_4_blob 0=0 1=2 11=2 2=2 12=2 3=0 4=0 5=1 +Convolution conv2d_16 1 1 max_pooling2d_4_blob conv2d_16_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=73728 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_16 1 1 conv2d_16_blob batch_normalization_16_blob 0=128 1=1.000000e-03 +ReLU activation_16 1 1 batch_normalization_16_blob activation_16_blob 0=0.000000e+00 1=0 +Split activation_16_Split 1 2 activation_16_blob activation_16_Split_blob_idx_0 activation_16_Split_blob_idx_1 +Convolution conv2d_17 1 1 activation_16_Split_blob_idx_0 conv2d_17_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=147456 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_17 1 1 conv2d_17_blob batch_normalization_17_blob 0=128 1=1.000000e-03 +ReLU activation_17 1 1 batch_normalization_17_blob activation_17_blob 0=0.000000e+00 1=0 +Convolution conv2d_18 1 1 activation_17_blob conv2d_18_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=147456 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_18 1 1 conv2d_18_blob batch_normalization_18_blob 0=128 1=1.000000e-03 +BinaryOp add_6 2 1 batch_normalization_18_blob activation_16_Split_blob_idx_1 add_6_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_18 1 1 add_6_blob activation_18_blob 0=0.000000e+00 1=0 +Split activation_18_Split 1 2 activation_18_blob activation_18_Split_blob_idx_0 activation_18_Split_blob_idx_1 +Convolution conv2d_19 1 1 activation_18_Split_blob_idx_0 conv2d_19_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=147456 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_19 1 1 conv2d_19_blob batch_normalization_19_blob 0=128 1=1.000000e-03 +ReLU activation_19 1 1 batch_normalization_19_blob activation_19_blob 0=0.000000e+00 1=0 +Convolution conv2d_20 1 1 activation_19_blob conv2d_20_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=147456 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_20 1 1 conv2d_20_blob batch_normalization_20_blob 0=128 1=1.000000e-03 +BinaryOp add_7 2 1 batch_normalization_20_blob activation_18_Split_blob_idx_1 add_7_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_20 1 1 add_7_blob activation_20_blob 0=0.000000e+00 1=0 +Split activation_20_Split 1 2 activation_20_blob activation_20_Split_blob_idx_0 activation_20_Split_blob_idx_1 +Convolution conv2d_21 1 1 activation_20_Split_blob_idx_0 conv2d_21_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=147456 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_21 1 1 conv2d_21_blob batch_normalization_21_blob 0=128 1=1.000000e-03 +ReLU activation_21 1 1 batch_normalization_21_blob activation_21_blob 0=0.000000e+00 1=0 +Convolution conv2d_22 1 1 activation_21_blob conv2d_22_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=147456 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_22 1 1 conv2d_22_blob batch_normalization_22_blob 0=128 1=1.000000e-03 +BinaryOp add_8 2 1 batch_normalization_22_blob activation_20_Split_blob_idx_1 add_8_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_22 1 1 add_8_blob activation_22_blob 0=0.000000e+00 1=0 +Split activation_22_Split 1 2 activation_22_blob activation_22_Split_blob_idx_0 activation_22_Split_blob_idx_1 +Convolution conv2d_23 1 1 activation_22_Split_blob_idx_0 conv2d_23_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=147456 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_23 1 1 conv2d_23_blob batch_normalization_23_blob 0=128 1=1.000000e-03 +ReLU activation_23 1 1 batch_normalization_23_blob activation_23_blob 0=0.000000e+00 1=0 +Convolution conv2d_24 1 1 activation_23_blob conv2d_24_blob 0=128 1=3 2=1 3=1 4=-233 5=1 6=147456 9=0 11=3 12=1 13=1 +BatchNorm batch_normalization_24 1 1 conv2d_24_blob batch_normalization_24_blob 0=128 1=1.000000e-03 +BinaryOp add_9 2 1 batch_normalization_24_blob activation_22_Split_blob_idx_1 add_9_blob 0=0 1=0 2=0.000000e+00 +ReLU activation_24 1 1 add_9_blob activation_24_blob 0=0.000000e+00 1=0 +Split activation_24_Split 1 2 activation_24_blob activation_24_Split_blob_idx_0 activation_24_Split_blob_idx_1 +Convolution conv2d_25 1 1 activation_24_Split_blob_idx_0 conv2d_25_blob 0=2 1=3 2=1 3=1 4=-233 5=1 6=2304 9=0 11=3 12=1 13=1 +Softmax conv2d_25_Softmax 1 1 conv2d_25_blob conv2d_25_Softmax_blob 0=0 +Convolution conv2d_26 1 1 activation_24_Split_blob_idx_1 conv2d_26_blob 0=6 1=3 2=1 3=1 4=-233 5=1 6=6912 9=0 11=3 12=1 13=1 +Concat concatenate_1 2 1 conv2d_26_blob conv2d_25_Softmax_blob concatenate_1_blob 0=0 diff --git a/dsexample_lib/Makefile b/dsexample_lib/Makefile new file mode 100755 index 0000000..4d94b7a --- /dev/null +++ b/dsexample_lib/Makefile @@ -0,0 +1,25 @@ +################################################################################ +# Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +################################################################################# + +all: + gcc -ggdb -c -o dsexample_lib.o -fPIC dsexample_lib.c + ar rcs libdsexample.a dsexample_lib.o diff --git a/dsexample_lib/dsexample_lib.c b/dsexample_lib/dsexample_lib.c new file mode 100755 index 0000000..086ba74 --- /dev/null +++ b/dsexample_lib/dsexample_lib.c @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "dsexample_lib.h" +#include +#include + +struct DsExampleCtx +{ + DsExampleInitParams initParams; +}; + +DsExampleCtx * +DsExampleCtxInit (DsExampleInitParams * initParams) +{ + DsExampleCtx *ctx = (DsExampleCtx *) calloc (1, sizeof (DsExampleCtx)); + ctx->initParams = *initParams; + return ctx; +} + +// In case of an actual processing library, processing on data wil be completed +// in this function and output will be returned +DsExampleOutput * +DsExampleProcess (DsExampleCtx * ctx, unsigned char *data) +{ + DsExampleOutput *out = + (DsExampleOutput*)calloc (1, sizeof (DsExampleOutput)); + + if (data != NULL) + { + // Process your data here + } + // Fill output structure using processed output + // Here, we fake some detected objects and labels + if (ctx->initParams.fullFrame) + { + out->numObjects = 2; + out->object[0] = (DsExampleObject) + { + (float)(ctx->initParams.processingWidth) / 8, + (float)(ctx->initParams.processingHeight) / 8, + (float)(ctx->initParams.processingWidth) / 8, + (float)(ctx->initParams.processingHeight) / 8, "Obj0" + }; + + out->object[1] = (DsExampleObject) + { + (float)(ctx->initParams.processingWidth) / 2, + (float)(ctx->initParams.processingHeight) / 2, + (float)(ctx->initParams.processingWidth) / 8, + (float)(ctx->initParams.processingHeight) / 8, "Obj1" + }; + } + else + { + out->numObjects = 1; + out->object[0] = (DsExampleObject) + { + (float)(ctx->initParams.processingWidth) / 8, + (float)(ctx->initParams.processingHeight) / 8, + (float)(ctx->initParams.processingWidth) / 8, + (float)(ctx->initParams.processingHeight) / 8, "" + }; + // Set the object label + snprintf (out->object[0].label, 64, "Obj_label"); + } + + return out; +} + +void +DsExampleCtxDeinit (DsExampleCtx * ctx) +{ + free (ctx); +} diff --git a/dsexample_lib/dsexample_lib.h b/dsexample_lib/dsexample_lib.h new file mode 100755 index 0000000..5920b39 --- /dev/null +++ b/dsexample_lib/dsexample_lib.h @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __DSEXAMPLE_LIB__ +#define __DSEXAMPLE_LIB__ + +#define MAX_LABEL_SIZE 128 +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DsExampleCtx DsExampleCtx; + +// Init parameters structure as input, required for instantiating dsexample_lib +typedef struct +{ + // Width at which frame/object will be scaled + int processingWidth; + // height at which frame/object will be scaled + int processingHeight; + // Flag to indicate whether operating on crops of full frame + int fullFrame; +} DsExampleInitParams; + +// Detected/Labelled object structure, stores bounding box info along with label +typedef struct +{ + float left; + float top; + float width; + float height; + char label[MAX_LABEL_SIZE]; +} DsExampleObject; + +// Output data returned after processing +typedef struct +{ + int numObjects; + DsExampleObject object[4]; +} DsExampleOutput; + +// Initialize library context +DsExampleCtx * DsExampleCtxInit (DsExampleInitParams *init_params); + +// Dequeue processed output +DsExampleOutput *DsExampleProcess (DsExampleCtx *ctx, unsigned char *data); + +// Deinitialize library context +void DsExampleCtxDeinit (DsExampleCtx *ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dsexample_lib/dsexample_lib.o b/dsexample_lib/dsexample_lib.o new file mode 100644 index 0000000..3932d2e Binary files /dev/null and b/dsexample_lib/dsexample_lib.o differ diff --git a/dsexample_lib/libdsexample.a b/dsexample_lib/libdsexample.a new file mode 100644 index 0000000..7c69e61 Binary files /dev/null and b/dsexample_lib/libdsexample.a differ diff --git a/gstdsexample.cpp b/gstdsexample.cpp new file mode 100755 index 0000000..1948519 --- /dev/null +++ b/gstdsexample.cpp @@ -0,0 +1,1198 @@ +/** + * Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +//TODO thainq: include header +#include "iostream" +#include "structs.h" +#include "LPRprocessor.h" +#include "thread" +#include +#include "mutex" +#include "DetectorCOCO.h" +// + +#include +#include +#include +#include +#include +#include +#include "gstdsexample.h" +#include +GST_DEBUG_CATEGORY_STATIC (gst_dsexample_debug); +#define GST_CAT_DEFAULT gst_dsexample_debug +#define USE_EGLIMAGE 1 +/* enable to write transformed cvmat to files */ +/* #define DSEXAMPLE_DEBUG */ +static GQuark _dsmeta_quark = 0; + +//TODO thainq init variable +int status_init = false; +std::queue qLicensePlate; +std::vector listLicensePlate; +std::vector listPushedTrackID; +std::mutex mutexThread; +// + +/* Enum to identify properties */ +enum +{ + PROP_0, + PROP_UNIQUE_ID, + PROP_PROCESSING_WIDTH, + PROP_PROCESSING_HEIGHT, + PROP_PROCESS_FULL_FRAME, + PROP_BLUR_OBJECTS, + PROP_GPU_DEVICE_ID +}; + +#define CHECK_NVDS_MEMORY_AND_GPUID(object, surface) \ + ({ int _errtype=0;\ + do { \ + if ((surface->memType == NVBUF_MEM_DEFAULT || surface->memType == NVBUF_MEM_CUDA_DEVICE) && \ + (surface->gpuId != object->gpu_id)) { \ + GST_ELEMENT_ERROR (object, RESOURCE, FAILED, \ + ("Input surface gpu-id doesnt match with configured gpu-id for element," \ + " please allocate input using unified memory, or use same gpu-ids"),\ + ("surface-gpu-id=%d,%s-gpu-id=%d",surface->gpuId,GST_ELEMENT_NAME(object),\ + object->gpu_id)); \ + _errtype = 1;\ + } \ + } while(0); \ + _errtype; \ + }) + + +/* Default values for properties */ +#define DEFAULT_UNIQUE_ID 15 +#define DEFAULT_PROCESSING_WIDTH 640 +#define DEFAULT_PROCESSING_HEIGHT 480 +#define DEFAULT_PROCESS_FULL_FRAME TRUE +#define DEFAULT_BLUR_OBJECTS FALSE +#define DEFAULT_GPU_ID 0 + +#define RGB_BYTES_PER_PIXEL 3 +#define RGBA_BYTES_PER_PIXEL 4 +#define Y_BYTES_PER_PIXEL 1 +#define UV_BYTES_PER_PIXEL 2 + +#define MIN_INPUT_OBJECT_WIDTH 16 +#define MIN_INPUT_OBJECT_HEIGHT 16 + +#define CHECK_NPP_STATUS(npp_status,error_str) do { \ + if ((npp_status) != NPP_SUCCESS) { \ + g_print ("Error: %s in %s at line %d: NPP Error %d\n", \ + error_str, __FILE__, __LINE__, npp_status); \ + goto error; \ + } \ +} while (0) + +#define CHECK_CUDA_STATUS(cuda_status,error_str) do { \ + if ((cuda_status) != cudaSuccess) { \ + g_print ("Error: %s in %s at line %d (%s)\n", \ + error_str, __FILE__, __LINE__, cudaGetErrorName(cuda_status)); \ + goto error; \ + } \ +} while (0) + +/* By default NVIDIA Hardware allocated memory flows through the pipeline. We + * will be processing on this type of memory only. */ +#define GST_CAPS_FEATURE_MEMORY_NVMM "memory:NVMM" +static GstStaticPadTemplate gst_dsexample_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES + (GST_CAPS_FEATURE_MEMORY_NVMM, + "{ NV12, RGBA, I420 }"))); + +static GstStaticPadTemplate gst_dsexample_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES + (GST_CAPS_FEATURE_MEMORY_NVMM, + "{ NV12, RGBA, I420 }"))); + +/* Define our element type. Standard GObject/GStreamer boilerplate stuff */ +#define gst_dsexample_parent_class parent_class +G_DEFINE_TYPE (GstDsExample, gst_dsexample, GST_TYPE_BASE_TRANSFORM); + +static void gst_dsexample_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_dsexample_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_dsexample_set_caps (GstBaseTransform * btrans, + GstCaps * incaps, GstCaps * outcaps); +static gboolean gst_dsexample_start (GstBaseTransform * btrans); +static gboolean gst_dsexample_stop (GstBaseTransform * btrans); + +static GstFlowReturn gst_dsexample_transform_ip (GstBaseTransform * + btrans, GstBuffer * inbuf); + +static void +attach_metadata_full_frame (GstDsExample * dsexample, NvDsFrameMeta *frame_meta, + gdouble scale_ratio, DsExampleOutput * output, guint batch_id); +static void attach_metadata_object (GstDsExample * dsexample, + NvDsObjectMeta * obj_meta, DsExampleOutput * output); + +/* Install properties, set sink and src pad capabilities, override the required + * functions of the base class, These are common to all instances of the + * element. + */ +static void +gst_dsexample_class_init (GstDsExampleClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseTransformClass *gstbasetransform_class; + + /* Indicates we want to use DS buf api */ + g_setenv ("DS_NEW_BUFAPI", "1", TRUE); + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasetransform_class = (GstBaseTransformClass *) klass; + + /* Overide base class functions */ + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_dsexample_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_dsexample_get_property); + + gstbasetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_dsexample_set_caps); + gstbasetransform_class->start = GST_DEBUG_FUNCPTR (gst_dsexample_start); + gstbasetransform_class->stop = GST_DEBUG_FUNCPTR (gst_dsexample_stop); + + gstbasetransform_class->transform_ip = + GST_DEBUG_FUNCPTR (gst_dsexample_transform_ip); + + /* Install properties */ + g_object_class_install_property (gobject_class, PROP_UNIQUE_ID, + g_param_spec_uint ("unique-id", + "Unique ID", + "Unique ID for the element. Can be used to identify output of the" + " element", 0, G_MAXUINT, DEFAULT_UNIQUE_ID, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_PROCESSING_WIDTH, + g_param_spec_int ("processing-width", + "Processing Width", + "Width of the input buffer to algorithm", + 1, G_MAXINT, DEFAULT_PROCESSING_WIDTH, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_PROCESSING_HEIGHT, + g_param_spec_int ("processing-height", + "Processing Height", + "Height of the input buffer to algorithm", + 1, G_MAXINT, DEFAULT_PROCESSING_HEIGHT, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_PROCESS_FULL_FRAME, + g_param_spec_boolean ("full-frame", + "Full frame", + "Enable to process full frame or disable to process objects detected" + "by primary detector", DEFAULT_PROCESS_FULL_FRAME, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_BLUR_OBJECTS, + g_param_spec_boolean ("blur-objects", + "Blur Objects", + "Enable to blur the objects detected in full-frame=0 mode" + "by primary detector", DEFAULT_BLUR_OBJECTS, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_GPU_DEVICE_ID, + g_param_spec_uint ("gpu-id", + "Set GPU Device ID", + "Set GPU Device ID", 0, + G_MAXUINT, 0, + GParamFlags + (G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY))); + /* Set sink and src pad capabilities */ + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_dsexample_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_dsexample_sink_template)); + + /* Set metadata describing the element */ + gst_element_class_set_details_simple (gstelement_class, + "DsExample plugin", + "DsExample Plugin", + "Process a 3rdparty example algorithm on objects / full frame", + "NVIDIA Corporation. Post on Deepstream for Tesla forum for any queries " + "@ https://devtalk.nvidia.com/default/board/209/"); +} + +static void +gst_dsexample_init (GstDsExample * dsexample) +{ + GstBaseTransform *btrans = GST_BASE_TRANSFORM (dsexample); + + /* We will not be generating a new buffer. Just adding / updating + * metadata. */ + gst_base_transform_set_in_place (GST_BASE_TRANSFORM (btrans), TRUE); + /* We do not want to change the input caps. Set to passthrough. transform_ip + * is still called. */ + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (btrans), TRUE); + + /* Initialize all property variables to default values */ + dsexample->unique_id = DEFAULT_UNIQUE_ID; + dsexample->processing_width = DEFAULT_PROCESSING_WIDTH; + dsexample->processing_height = DEFAULT_PROCESSING_HEIGHT; + dsexample->process_full_frame = DEFAULT_PROCESS_FULL_FRAME; + dsexample->blur_objects = DEFAULT_BLUR_OBJECTS; + dsexample->gpu_id = DEFAULT_GPU_ID; + + /* This quark is required to identify NvDsMeta when iterating through + * the buffer metadatas */ + if (!_dsmeta_quark) + _dsmeta_quark = g_quark_from_static_string (NVDS_META_STRING); +} + +/* Function called when a property of the element is set. Standard boilerplate. + */ +static void +gst_dsexample_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (object); + switch (prop_id) { + case PROP_UNIQUE_ID: + dsexample->unique_id = g_value_get_uint (value); + break; + case PROP_PROCESSING_WIDTH: + dsexample->processing_width = g_value_get_int (value); + break; + case PROP_PROCESSING_HEIGHT: + dsexample->processing_height = g_value_get_int (value); + break; + case PROP_PROCESS_FULL_FRAME: + dsexample->process_full_frame = g_value_get_boolean (value); + break; + case PROP_BLUR_OBJECTS: + dsexample->blur_objects = g_value_get_boolean (value); + break; + case PROP_GPU_DEVICE_ID: + dsexample->gpu_id = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* Function called when a property of the element is requested. Standard + * boilerplate. + */ +static void +gst_dsexample_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (object); + + switch (prop_id) { + case PROP_UNIQUE_ID: + g_value_set_uint (value, dsexample->unique_id); + break; + case PROP_PROCESSING_WIDTH: + g_value_set_int (value, dsexample->processing_width); + break; + case PROP_PROCESSING_HEIGHT: + g_value_set_int (value, dsexample->processing_height); + break; + case PROP_PROCESS_FULL_FRAME: + g_value_set_boolean (value, dsexample->process_full_frame); + break; + case PROP_BLUR_OBJECTS: + g_value_set_boolean (value, dsexample->blur_objects); + break; + case PROP_GPU_DEVICE_ID: + g_value_set_uint (value, dsexample->gpu_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * Initialize all resources and start the output thread + */ +static gboolean +gst_dsexample_start (GstBaseTransform * btrans) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + NvBufSurfaceCreateParams create_params; + DsExampleInitParams init_params = + { dsexample->processing_width, dsexample->processing_height, + dsexample->process_full_frame + }; + + GstQuery *queryparams = NULL; + guint batch_size = 1; + int val = -1; + + /* Algorithm specific initializations and resource allocation. */ + dsexample->dsexamplelib_ctx = DsExampleCtxInit (&init_params); + + GST_DEBUG_OBJECT (dsexample, "ctx lib %p \n", dsexample->dsexamplelib_ctx); + + CHECK_CUDA_STATUS (cudaSetDevice (dsexample->gpu_id), + "Unable to set cuda device"); + + cudaDeviceGetAttribute (&val, cudaDevAttrIntegrated, dsexample->gpu_id); + dsexample->is_integrated = val; + + dsexample->batch_size = 1; + queryparams = gst_nvquery_batch_size_new (); + if (gst_pad_peer_query (GST_BASE_TRANSFORM_SINK_PAD (btrans), queryparams) + || gst_pad_peer_query (GST_BASE_TRANSFORM_SRC_PAD (btrans), queryparams)) { + if (gst_nvquery_batch_size_parse (queryparams, &batch_size)) { + dsexample->batch_size = batch_size; + } + } + GST_DEBUG_OBJECT (dsexample, "Setting batch-size %d \n", + dsexample->batch_size); + gst_query_unref (queryparams); + + if (dsexample->process_full_frame && dsexample->blur_objects) { + GST_ERROR ("Error: does not support blurring while processing full frame"); + goto error; + } + +#ifndef WITH_OPENCV + if (dsexample->blur_objects) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("OpenCV has been deprecated, hence object blurring will not work." + "Enable OpenCV compilation in gst-dsexample Makefile by setting 'WITH_OPENCV:=1"), (NULL)); + goto error; + } +#endif + + CHECK_CUDA_STATUS (cudaStreamCreate (&dsexample->cuda_stream), + "Could not create cuda stream"); + + if (dsexample->inter_buf) + NvBufSurfaceDestroy (dsexample->inter_buf); + dsexample->inter_buf = NULL; + + /* An intermediate buffer for NV12/RGBA to BGR conversion will be + * required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */ + create_params.gpuId = dsexample->gpu_id; + create_params.width = dsexample->processing_width; + create_params.height = dsexample->processing_height; + create_params.size = 0; + create_params.colorFormat = NVBUF_COLOR_FORMAT_RGBA; + create_params.layout = NVBUF_LAYOUT_PITCH; + + if(dsexample->is_integrated) { + create_params.memType = NVBUF_MEM_DEFAULT; + } + else { + create_params.memType = NVBUF_MEM_CUDA_PINNED; + } + + if (NvBufSurfaceCreate (&dsexample->inter_buf, 1, + &create_params) != 0) { + GST_ERROR ("Error: Could not allocate internal buffer for dsexample"); + goto error; + } + + /* Create host memory for storing converted/scaled interleaved RGB data */ + CHECK_CUDA_STATUS (cudaMallocHost (&dsexample->host_rgb_buf, + dsexample->processing_width * dsexample->processing_height * + RGB_BYTES_PER_PIXEL), "Could not allocate cuda host buffer"); + + GST_DEBUG_OBJECT (dsexample, "allocated cuda buffer %p \n", + dsexample->host_rgb_buf); + +#ifdef WITH_OPENCV + /* CV Mat containing interleaved RGB data. This call does not allocate memory. + * It uses host_rgb_buf as data. */ + dsexample->cvmat = + new cv::Mat (dsexample->processing_height, dsexample->processing_width, + CV_8UC3, dsexample->host_rgb_buf, + dsexample->processing_width * RGB_BYTES_PER_PIXEL); + + if (!dsexample->cvmat) + goto error; + + GST_DEBUG_OBJECT (dsexample, "created CV Mat\n"); +#endif + + return TRUE; +error: + if (dsexample->host_rgb_buf) { + cudaFreeHost (dsexample->host_rgb_buf); + dsexample->host_rgb_buf = NULL; + } + + if (dsexample->cuda_stream) { + cudaStreamDestroy (dsexample->cuda_stream); + dsexample->cuda_stream = NULL; + } + if (dsexample->dsexamplelib_ctx) + DsExampleCtxDeinit (dsexample->dsexamplelib_ctx); + return FALSE; +} + +/** + * Stop the output thread and free up all the resources + */ +static gboolean +gst_dsexample_stop (GstBaseTransform * btrans) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + + if (dsexample->inter_buf) + NvBufSurfaceDestroy(dsexample->inter_buf); + dsexample->inter_buf = NULL; + + if (dsexample->cuda_stream) + cudaStreamDestroy (dsexample->cuda_stream); + dsexample->cuda_stream = NULL; + +#ifdef WITH_OPENCV + delete dsexample->cvmat; + dsexample->cvmat = NULL; +#endif + + if (dsexample->host_rgb_buf) { + cudaFreeHost (dsexample->host_rgb_buf); + dsexample->host_rgb_buf = NULL; + } + + GST_DEBUG_OBJECT (dsexample, "deleted CV Mat \n"); + + /* Deinit the algorithm library */ + DsExampleCtxDeinit (dsexample->dsexamplelib_ctx); + dsexample->dsexamplelib_ctx = NULL; + + GST_DEBUG_OBJECT (dsexample, "ctx lib released \n"); + + return TRUE; +} + +/** + * Called when source / sink pad capabilities have been negotiated. + */ +static gboolean +gst_dsexample_set_caps (GstBaseTransform * btrans, GstCaps * incaps, + GstCaps * outcaps) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + /* Save the input video information, since this will be required later. */ + gst_video_info_from_caps (&dsexample->video_info, incaps); + + if (dsexample->blur_objects && !dsexample->process_full_frame) { + /* requires RGBA format for blurring the objects in opencv */ + if (dsexample->video_info.finfo->format != GST_VIDEO_FORMAT_RGBA) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("input format should be RGBA when using blur-objects property"), (NULL)); + goto error; + } + } + + return TRUE; + +error: + return FALSE; +} + +/** + * Scale the entire frame to the processing resolution maintaining aspect ratio. + * Or crop and scale objects to the processing resolution maintaining the aspect + * ratio. Remove the padding required by hardware and convert from RGBA to RGB + * using openCV. These steps can be skipped if the algorithm can work with + * padded data and/or can work with RGBA. + */ +static GstFlowReturn +get_converted_mat (GstDsExample * dsexample, NvBufSurface *input_buf, gint idx, + NvOSD_RectParams * crop_rect_params, gdouble & ratio, gint input_width, + gint input_height, int source_id, cv::Mat &out_mat) +{ + NvBufSurfTransform_Error err; + NvBufSurfTransformConfigParams transform_config_params; + NvBufSurfTransformParams transform_params; + NvBufSurfTransformRect src_rect; + NvBufSurfTransformRect dst_rect; + NvBufSurface ip_surf; +#ifdef WITH_OPENCV + cv::Mat in_mat; +#endif + ip_surf = *input_buf; + + ip_surf.numFilled = ip_surf.batchSize = 1; + ip_surf.surfaceList = &(input_buf->surfaceList[idx]); + + gint src_left = GST_ROUND_UP_2((unsigned int)crop_rect_params->left); + gint src_top = GST_ROUND_UP_2((unsigned int)crop_rect_params->top); + gint src_width = GST_ROUND_DOWN_2((unsigned int)crop_rect_params->width); + gint src_height = GST_ROUND_DOWN_2((unsigned int)crop_rect_params->height); + + /* Maintain aspect ratio */ + double hdest = dsexample->processing_width * src_height / (double) src_width; + double wdest = dsexample->processing_height * src_width / (double) src_height; + guint dest_width, dest_height; + + if (hdest <= dsexample->processing_height) { + dest_width = dsexample->processing_width; + dest_height = hdest; + } else { + dest_width = wdest; + dest_height = dsexample->processing_height; + } + + /* Configure transform session parameters for the transformation */ + transform_config_params.compute_mode = NvBufSurfTransformCompute_Default; + transform_config_params.gpu_id = dsexample->gpu_id; + transform_config_params.cuda_stream = dsexample->cuda_stream; + + /* Set the transform session parameters for the conversions executed in this + * thread. */ + err = NvBufSurfTransformSetSessionParams (&transform_config_params); + if (err != NvBufSurfTransformError_Success) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("NvBufSurfTransformSetSessionParams failed with error %d", err), (NULL)); + goto error; + } + + /* Calculate scaling ratio while maintaining aspect ratio */ + ratio = MIN (1.0 * dest_width/ src_width, 1.0 * dest_height / src_height); + + if ((crop_rect_params->width == 0) || (crop_rect_params->height == 0)) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:crop_rect_params dimensions are zero",__func__), (NULL)); + goto error; + } + +#ifdef __aarch64__ + if (ratio <= 1.0 / 16 || ratio >= 16.0) { + /* Currently cannot scale by ratio > 16 or < 1/16 for Jetson */ + goto error; + } +#endif + /* Set the transform ROIs for source and destination */ + src_rect = {(guint)src_top, (guint)src_left, (guint)src_width, (guint)src_height}; + dst_rect = {0, 0, (guint)dest_width, (guint)dest_height}; + + /* Set the transform parameters */ + transform_params.src_rect = &src_rect; + transform_params.dst_rect = &dst_rect; + transform_params.transform_flag = + NVBUFSURF_TRANSFORM_FILTER | NVBUFSURF_TRANSFORM_CROP_SRC | + NVBUFSURF_TRANSFORM_CROP_DST; + transform_params.transform_filter = NvBufSurfTransformInter_Default; + + /* Memset the memory */ + NvBufSurfaceMemSet (dsexample->inter_buf, 0, 0, 0); + + GST_DEBUG_OBJECT (dsexample, "Scaling and converting input buffer\n"); + + /* Transformation scaling+format conversion if any. */ + err = NvBufSurfTransform (&ip_surf, dsexample->inter_buf, &transform_params); + if (err != NvBufSurfTransformError_Success) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("NvBufSurfTransform failed with error %d while converting buffer", err), + (NULL)); + goto error; + } + /* Map the buffer so that it can be accessed by CPU */ + if (NvBufSurfaceMap (dsexample->inter_buf, 0, 0, NVBUF_MAP_READ) != 0){ + goto error; + } + if(dsexample->inter_buf->memType == NVBUF_MEM_SURFACE_ARRAY) { + /* Cache the mapped data for CPU access */ + NvBufSurfaceSyncForCpu (dsexample->inter_buf, 0, 0); + } + +#ifdef WITH_OPENCV + /* Use openCV to remove padding and convert RGBA to BGR. Can be skipped if + * algorithm can handle padded RGBA data. */ + in_mat = + cv::Mat (dsexample->processing_height, dsexample->processing_width, + CV_8UC4, dsexample->inter_buf->surfaceList[0].mappedAddr.addr[0], + dsexample->inter_buf->surfaceList[0].pitch); + +#if (CV_MAJOR_VERSION >= 4) + //todo thainq: comment code + // cv::cvtColor (in_mat, *dsexample->cvmat, cv::COLOR_RGBA2BGR); + + //todo thainq: cvt img + cv::cvtColor(in_mat, out_mat, cv::COLOR_RGBA2BGR); +#else + //todo thainq: comment code + // cv::cvtColor (in_mat, *dsexample->cvmat, CV_RGBA2BGR); + + //todo thainq: cvt img + cv::cvtColor(in_mat, out_mat, CV_RGBA2BGR); + +#endif +#endif + if (NvBufSurfaceUnMap (dsexample->inter_buf, 0, 0)){ + goto error; + } + + if(dsexample->is_integrated) { +#ifdef __aarch64__ + /* To use the converted buffer in CUDA, create an EGLImage and then use + * CUDA-EGL interop APIs */ + if (USE_EGLIMAGE) { + if (NvBufSurfaceMapEglImage (dsexample->inter_buf, 0) !=0 ) { + goto error; + } + + /* dsexample->inter_buf->surfaceList[0].mappedAddr.eglImage + * Use interop APIs cuGraphicsEGLRegisterImage and + * cuGraphicsResourceGetMappedEglFrame to access the buffer in CUDA */ + + /* Destroy the EGLImage */ + NvBufSurfaceUnMapEglImage (dsexample->inter_buf, 0); + } +#endif + } + + /* We will first convert only the Region of Interest (the entire frame or the + * object bounding box) to RGB and then scale the converted RGB frame to + * processing resolution. */ + return GST_FLOW_OK; + +error: + return GST_FLOW_ERROR; +} + +#ifdef WITH_OPENCV +/* + * Blur the detected objects when processing in object mode (full-frame=0) + */ +static GstFlowReturn +blur_objects (GstDsExample * dsexample, gint idx, + NvOSD_RectParams * crop_rect_params, cv::Mat in_mat) +{ + cv::Rect crop_rect; + + if ((crop_rect_params->width == 0) || (crop_rect_params->height == 0)) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:crop_rect_params dimensions are zero",__func__), (NULL)); + return GST_FLOW_ERROR; + } + +/* rectangle for cropped objects */ + crop_rect = cv::Rect (crop_rect_params->left, crop_rect_params->top, + crop_rect_params->width, crop_rect_params->height); + +/* apply gaussian blur to the detected objects */ + GaussianBlur(in_mat(crop_rect), in_mat(crop_rect), cv::Size(15,15), 4); + + return GST_FLOW_OK; +} +#endif + +/** + * Called when element recieves an input buffer from upstream element. + */ + +static GstFlowReturn +gst_dsexample_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf) +{ + + //TODO thainq init platedetector + if (!status_init){ + std::cout << "init...." << std::endl; + status_init = true; + LPRprocessor *lprProcessor = new LPRprocessor(qLicensePlate, mutexThread); + lprProcessor->start(); + + DetectorCOCO::getInst()._init(); + cv::Mat img = cv::imread("/home/thai/Desktop/5889307c80ebd7a17640001952053c47.jpeg"); + for (int i=0 ; i<100000 ; i++){ + std::vector rs = DetectorCOCO::getInst().predict(img.clone(), "chair"); + std::cout << "rs size = " << rs.size() << std::endl; + for (auto it : rs){ + std::cout << "conf = " << it.conf << std::endl; + std::cout << "class id = " << it.label << std::endl; + std::cout << "----------------" << std::endl; + } + } + + // CropLP::getInst()._init(); + // cv::Mat img = cv::imread("/media/thai/A0B6A6B3B6A688FC2/code/PROJECT_BI/CLONE/tensorrtx/unet/samples/3437_gxrIguHlOUmNShpighWT.jpg"); + // for (int i=0 ; i<10000 ; i++){ + // std::vector result = CropLP::getInst().predict(img, SQUARE); + // cv::imwrite("/home/thai/Desktop/test-OCR/test_segment/cropped.jpg", result[0]); + // } + + + // LicensePlateRecognizer licensePlateRecognizer; + + // cv::Mat img_crop = cv::imread("/home/thai/Desktop/save_frame/crop.jpg"); + // PlateDetail plateDetail = licensePlateRecognizer.recognition(img_crop, SQUARE); + // std::cout << "OCR = " << plateDetail.ocr << std::endl; + // std::cout << "color = " << plateDetail.color << std::endl; + // cv::imwrite("/home/thai/Desktop/save_frame/crop_1.jpg", plateDetail.plate); + + } + + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + GstMapInfo in_map_info; + GstFlowReturn flow_ret = GST_FLOW_ERROR; + gdouble scale_ratio = 1.0; + DsExampleOutput *output; + + NvBufSurface *surface = NULL; + NvDsBatchMeta *batch_meta = NULL; + NvDsFrameMeta *frame_meta = NULL; + NvDsMetaList * l_frame = NULL; + guint i = 0; + + dsexample->frame_num++; + CHECK_CUDA_STATUS (cudaSetDevice (dsexample->gpu_id), + "Unable to set cuda device"); + + memset (&in_map_info, 0, sizeof (in_map_info)); + if (!gst_buffer_map (inbuf, &in_map_info, GST_MAP_READ)) { + g_print ("Error: Failed to map gst buffer\n"); + goto error; + } + + nvds_set_input_system_timestamp (inbuf, GST_ELEMENT_NAME (dsexample)); + surface = (NvBufSurface *) in_map_info.data; + GST_DEBUG_OBJECT (dsexample, + "Processing Frame %" G_GUINT64_FORMAT " Surface %p\n", + dsexample->frame_num, surface); + + if (CHECK_NVDS_MEMORY_AND_GPUID (dsexample, surface)) + goto error; + + batch_meta = gst_buffer_get_nvds_batch_meta (inbuf); + if (batch_meta == nullptr) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("NvDsBatchMeta not found for input buffer."), (NULL)); + return GST_FLOW_ERROR; + } + + if (dsexample->process_full_frame) { + for (l_frame = batch_meta->frame_meta_list; l_frame != NULL; + l_frame = l_frame->next) + { + frame_meta = (NvDsFrameMeta *) (l_frame->data); + NvOSD_RectParams rect_params; + + // TODO thainq: init struct + LicensePlateItem licensePlateItem; + /* Scale the entire frame to processing resolution */ + rect_params.left = 0; + rect_params.top = 0; + rect_params.width = dsexample->video_info.width; + rect_params.height = dsexample->video_info.height; + + cv::Mat out_mat; + if (get_converted_mat (dsexample, surface, i, &rect_params, + scale_ratio, dsexample->video_info.width, + dsexample->video_info.height, frame_meta->source_id, out_mat) != GST_FLOW_OK) { + goto error; + } + + if (frame_meta->source_id == 0 || frame_meta->source_id == 1){ + //TODO thainq: add sourceID + licensePlateItem.sourceID = int(frame_meta->source_id); + + + for (NvDsMetaList *l_obj = frame_meta->obj_meta_list; l_obj != NULL; + l_obj = l_obj->next) + { + NvDsObjectMeta *obj = (NvDsObjectMeta *)l_obj->data; + //TODO thainq: add trackID + licensePlateItem.trackID = int(obj->object_id); + bool isClassify = false; + + // std::cout << "track id = " << int(obj->object_id) << std::endl; + + 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; + + //TODO thainq: add mode of license plate + if (std::string(label->result_label) == "long"){ + licensePlateItem.mode = LONG; + isClassify = true; + }else if (std::string(label->result_label) == "square"){ + licensePlateItem.mode = SQUARE; + isClassify = true; + } + } + } + + //TODO thainq: get coordinate object + int x = int(obj->rect_params.left * out_mat.cols / dsexample->video_info.width); + int y = int(obj->rect_params.top * out_mat.rows / dsexample->video_info.height); + int width = int(obj->rect_params.width * out_mat.cols / dsexample->video_info.width); + int height = int(obj->rect_params.height * out_mat.rows / dsexample->video_info.height); + + cv::Rect rectLicensePlate {x, y, width, height}; + cv::Mat imgCropPlate = out_mat(rectLicensePlate); + + //TODO thainq: check isClassify and image licenseplate + if (isClassify && !imgCropPlate.empty()){ + licensePlateItem.imgLicensePlate = imgCropPlate; + } + } + + //TODO thainq: check trackID in list + bool isContain = false; + for (int i=0 ; i= 3 && + (std::find(listPushedTrackID.begin(), listPushedTrackID.end(), listLicensePlate.at(i).trackID) != listPushedTrackID.end()) != 1 ){ + + mutexThread.lock(); + qLicensePlate.push(listLicensePlate.at(i)); + mutexThread.unlock(); + listPushedTrackID.push_back(listLicensePlate.at(i).trackID); + listLicensePlate.erase(listLicensePlate.begin() + i); + } + } + + if (listPushedTrackID.size() >= 20){ + listPushedTrackID.erase(listPushedTrackID.begin()); + } + + } + + + // std::cout << " ------------------------- " << std::endl; + /* Scale and convert the frame */ + // if (get_converted_mat (dsexample, surface, i, &rect_params, + // scale_ratio, dsexample->video_info.width, + // dsexample->video_info.height, ) != GST_FLOW_OK) { + // goto error; + // } + + /* Process to get the output */ + // TODO thainq: comment code +#ifdef WITH_OPENCV + // output = + // DsExampleProcess (dsexample->dsexamplelib_ctx, + // dsexample->cvmat->data); +#else + // output = + // DsExampleProcess (dsexample->dsexamplelib_ctx, + // (unsigned char *)dsexample->inter_buf->surfaceList[0].mappedAddr.addr[0]); +#endif + /* Attach the metadata for the full frame */ + // attach_metadata_full_frame (dsexample, frame_meta, scale_ratio, output, i); + i++; + // free (output); + } + + } else { + /* Using object crops as input to the algorithm. The objects are detected by + * the primary detector */ + NvDsMetaList * l_obj = NULL; + NvDsObjectMeta *obj_meta = NULL; + + if(!dsexample->is_integrated) { + if (dsexample->blur_objects) { + if (!(surface->memType == NVBUF_MEM_CUDA_UNIFIED || surface->memType == NVBUF_MEM_CUDA_PINNED)){ + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:need NVBUF_MEM_CUDA_UNIFIED or NVBUF_MEM_CUDA_PINNED memory for opencv blurring",__func__), (NULL)); + return GST_FLOW_ERROR; + } + } + } + + for (l_frame = batch_meta->frame_meta_list; l_frame != NULL; + l_frame = l_frame->next) + { + frame_meta = (NvDsFrameMeta *) (l_frame->data); + +#ifdef WITH_OPENCV + cv::Mat in_mat; + + if (dsexample->blur_objects) { + /* Map the buffer so that it can be accessed by CPU */ + if (surface->surfaceList[frame_meta->batch_id].mappedAddr.addr[0] == NULL){ + if (NvBufSurfaceMap (surface, frame_meta->batch_id, 0, NVBUF_MAP_READ_WRITE) != 0){ + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:buffer map to be accessed by CPU failed", __func__), (NULL)); + return GST_FLOW_ERROR; + } + } + + /* Cache the mapped data for CPU access */ + if(dsexample->inter_buf->memType == NVBUF_MEM_SURFACE_ARRAY) + NvBufSurfaceSyncForCpu (surface, frame_meta->batch_id, 0); + + in_mat = + cv::Mat (surface->surfaceList[frame_meta->batch_id].planeParams.height[0], + surface->surfaceList[frame_meta->batch_id].planeParams.width[0], CV_8UC4, + surface->surfaceList[frame_meta->batch_id].mappedAddr.addr[0], + surface->surfaceList[frame_meta->batch_id].planeParams.pitch[0]); + } +#endif + + for (l_obj = frame_meta->obj_meta_list; l_obj != NULL; + l_obj = l_obj->next) + { + obj_meta = (NvDsObjectMeta *) (l_obj->data); + + if (dsexample->blur_objects) { + /* gaussian blur the detected objects using opencv */ +#ifdef WITH_OPENCV + if (blur_objects (dsexample, frame_meta->batch_id, + &obj_meta->rect_params, in_mat) != GST_FLOW_OK) { + /* Error in blurring, skip processing on object. */ + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("blurring the object failed"), (NULL)); + if (NvBufSurfaceUnMap (surface, frame_meta->batch_id, 0)){ + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:buffer unmap to be accessed by CPU failed", __func__), (NULL)); + } + return GST_FLOW_ERROR; + } + continue; +#else + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("OpenCV has been deprecated, hence object blurring will not work." + "Enable OpenCV compilation in gst-dsexample Makefile by setting 'WITH_OPENCV:=1"), (NULL)); + return GST_FLOW_ERROR; +#endif + } + + /* Should not process on objects smaller than MIN_INPUT_OBJECT_WIDTH x MIN_INPUT_OBJECT_HEIGHT + * since it will cause hardware scaling issues. */ + if (obj_meta->rect_params.width < MIN_INPUT_OBJECT_WIDTH || + obj_meta->rect_params.height < MIN_INPUT_OBJECT_HEIGHT) + continue; + + /* Crop and scale the object */ + //todo thainq: comment code + // if (get_converted_mat (dsexample, + // surface, frame_meta->batch_id, &obj_meta->rect_params, + // scale_ratio, dsexample->video_info.width, + // dsexample->video_info.height) != GST_FLOW_OK) { + // /* Error in conversion, skip processing on object. */ + // continue; + // } + +#ifdef WITH_OPENCV + /* Process the object crop to obtain label */ + output = DsExampleProcess (dsexample->dsexamplelib_ctx, + dsexample->cvmat->data); +#else + /* Process the object crop to obtain label */ + output = DsExampleProcess (dsexample->dsexamplelib_ctx, + (unsigned char *)dsexample->inter_buf->surfaceList[0].mappedAddr.addr[0]); +#endif + + /* Attach labels for the object */ + attach_metadata_object (dsexample, obj_meta, output); + + free (output); + } + + if (dsexample->blur_objects) { + /* Cache the mapped data for device access */ + if(dsexample->inter_buf->memType == NVBUF_MEM_SURFACE_ARRAY) + NvBufSurfaceSyncForDevice (surface, frame_meta->batch_id, 0); + +#ifdef WITH_OPENCV +#ifdef DSEXAMPLE_DEBUG + /* Use openCV to remove padding and convert RGBA to BGR. Can be skipped if + * algorithm can handle padded RGBA data. */ +#if (CV_MAJOR_VERSION >= 4) + cv::cvtColor (in_mat, *dsexample->cvmat, cv::COLOR_RGBA2BGR); +#else + cv::cvtColor (in_mat, *dsexample->cvmat, CV_RGBA2BGR); +#endif + /* used to dump the converted mat to files for debug */ + static guint cnt = 0; + cv::imwrite("out_" + std::to_string (cnt) + ".jpeg", *dsexample->cvmat); + cnt++; +#endif +#endif + } + } + } + flow_ret = GST_FLOW_OK; + +error: + + nvds_set_output_system_timestamp (inbuf, GST_ELEMENT_NAME (dsexample)); + gst_buffer_unmap (inbuf, &in_map_info); + return flow_ret; +} + +/** + * Attach metadata for the full frame. We will be adding a new metadata. + */ +static void +attach_metadata_full_frame (GstDsExample * dsexample, NvDsFrameMeta *frame_meta, + gdouble scale_ratio, DsExampleOutput * output, guint batch_id) +{ + NvDsBatchMeta *batch_meta = frame_meta->base_meta.batch_meta; + NvDsObjectMeta *object_meta = NULL; + static gchar font_name[] = "Serif"; + GST_DEBUG_OBJECT (dsexample, "Attaching metadata %d\n", output->numObjects); + + for (gint i = 0; i < output->numObjects; i++) { + DsExampleObject *obj = &output->object[i]; + object_meta = nvds_acquire_obj_meta_from_pool(batch_meta); + NvOSD_RectParams & rect_params = object_meta->rect_params; + NvOSD_TextParams & text_params = object_meta->text_params; + + /* Assign bounding box coordinates */ + rect_params.left = obj->left; + rect_params.top = obj->top; + rect_params.width = obj->width; + rect_params.height = obj->height; + + /* Semi-transparent yellow background */ + rect_params.has_bg_color = 0; + rect_params.bg_color = (NvOSD_ColorParams) { + 1, 1, 0, 0.4}; + /* Red border of width 6 */ + rect_params.border_width = 3; + rect_params.border_color = (NvOSD_ColorParams) { + 1, 0, 0, 1}; + + /* Scale the bounding boxes proportionally based on how the object/frame was + * scaled during input */ + rect_params.left /= scale_ratio; + rect_params.top /= scale_ratio; + rect_params.width /= scale_ratio; + rect_params.height /= scale_ratio; + GST_DEBUG_OBJECT (dsexample, "Attaching rect%d of batch%u" + " left->%f top->%f width->%f" + " height->%f label->%s\n", i, batch_id, rect_params.left, + rect_params.top, rect_params.width, rect_params.height, obj->label); + + object_meta->object_id = UNTRACKED_OBJECT_ID; + g_strlcpy (object_meta->obj_label, obj->label, MAX_LABEL_SIZE); + /* display_text required heap allocated memory */ + text_params.display_text = g_strdup (obj->label); + /* Display text above the left top corner of the object */ + text_params.x_offset = rect_params.left; + text_params.y_offset = rect_params.top - 10; + /* Set black background for the text */ + text_params.set_bg_clr = 1; + text_params.text_bg_clr = (NvOSD_ColorParams) { + 0, 0, 0, 1}; + /* Font face, size and color */ + text_params.font_params.font_name = font_name; + text_params.font_params.font_size = 11; + text_params.font_params.font_color = (NvOSD_ColorParams) { + 1, 1, 1, 1}; + + nvds_add_obj_meta_to_frame(frame_meta, object_meta, NULL); + frame_meta->bInferDone = TRUE; + } +} + +/** + * Only update string label in an existing object metadata. No bounding boxes. + * We assume only one label per object is generated + */ +static void +attach_metadata_object (GstDsExample * dsexample, NvDsObjectMeta * obj_meta, + DsExampleOutput * output) +{ + if (output->numObjects == 0) + return; + NvDsBatchMeta *batch_meta = obj_meta->base_meta.batch_meta; + + NvDsClassifierMeta *classifier_meta = + nvds_acquire_classifier_meta_from_pool (batch_meta); + + classifier_meta->unique_component_id = dsexample->unique_id; + + NvDsLabelInfo *label_info = + nvds_acquire_label_info_meta_from_pool (batch_meta); + g_strlcpy (label_info->result_label, output->object[0].label, MAX_LABEL_SIZE); + nvds_add_label_info_meta_to_classifier(classifier_meta, label_info); + nvds_add_classifier_meta_to_object (obj_meta, classifier_meta); + + nvds_acquire_meta_lock (batch_meta); + NvOSD_TextParams & text_params = obj_meta->text_params; + NvOSD_RectParams & rect_params = obj_meta->rect_params; + + /* Below code to display the result */ + /* Set black background for the text + * display_text required heap allocated memory */ + if (text_params.display_text) { + gchar *conc_string = g_strconcat (text_params.display_text, " ", + output->object[0].label, NULL); + g_free (text_params.display_text); + text_params.display_text = conc_string; + } else { + /* Display text above the left top corner of the object */ + text_params.x_offset = rect_params.left; + text_params.y_offset = rect_params.top - 10; + text_params.display_text = g_strdup (output->object[0].label); + /* Font face, size and color */ + text_params.font_params.font_name = (char *)"Serif"; + text_params.font_params.font_size = 11; + text_params.font_params.font_color = (NvOSD_ColorParams) { + 1, 1, 1, 1}; + /* Set black background for the text */ + text_params.set_bg_clr = 1; + text_params.text_bg_clr = (NvOSD_ColorParams) { + 0, 0, 0, 1}; + } + nvds_release_meta_lock (batch_meta); +} + +/** + * Boiler plate for registering a plugin and an element. + */ +static gboolean +dsexample_plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_dsexample_debug, "dsexample", 0, + "dsexample plugin"); + + return gst_element_register (plugin, "dsexample", GST_RANK_PRIMARY, + GST_TYPE_DSEXAMPLE); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + nvdsgst_dsexample, + DESCRIPTION, dsexample_plugin_init, "6.0", LICENSE, BINARY_PACKAGE, URL) diff --git a/gstdsexample.h b/gstdsexample.h new file mode 100755 index 0000000..79b26bc --- /dev/null +++ b/gstdsexample.h @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __GST_DSEXAMPLE_H__ +#define __GST_DSEXAMPLE_H__ + +#include +#include + +/* Open CV headers */ +#ifdef WITH_OPENCV +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" +#endif + +#include +#include +#include "nvbufsurface.h" +#include "nvbufsurftransform.h" +#include "gst-nvquery.h" +#include "gstnvdsmeta.h" +#include "dsexample_lib/dsexample_lib.h" + +/* Package and library details required for plugin_init */ +#define PACKAGE "dsexample" +#define VERSION "1.0" +#define LICENSE "Proprietary" +#define DESCRIPTION "NVIDIA example plugin for integration with DeepStream on DGPU" +#define BINARY_PACKAGE "NVIDIA DeepStream 3rdparty IP integration example plugin" +#define URL "http://nvidia.com/" + + +G_BEGIN_DECLS +/* Standard boilerplate stuff */ +typedef struct _GstDsExample GstDsExample; +typedef struct _GstDsExampleClass GstDsExampleClass; + +/* Standard boilerplate stuff */ +#define GST_TYPE_DSEXAMPLE (gst_dsexample_get_type()) +#define GST_DSEXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DSEXAMPLE,GstDsExample)) +#define GST_DSEXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DSEXAMPLE,GstDsExampleClass)) +#define GST_DSEXAMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_DSEXAMPLE, GstDsExampleClass)) +#define GST_IS_DSEXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DSEXAMPLE)) +#define GST_IS_DSEXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DSEXAMPLE)) +#define GST_DSEXAMPLE_CAST(obj) ((GstDsExample *)(obj)) + +struct _GstDsExample +{ + GstBaseTransform base_trans; + + // Context of the custom algorithm library + DsExampleCtx *dsexamplelib_ctx; + + // Unique ID of the element. The labels generated by the element will be + // updated at index `unique_id` of attr_info array in NvDsObjectParams. + guint unique_id; + + // Frame number of the current input buffer + guint64 frame_num; + + // CUDA Stream used for allocating the CUDA task + cudaStream_t cuda_stream; + + // Host buffer to store RGB data for use by algorithm + void *host_rgb_buf; + + // the intermediate scratch buffer for conversions RGBA + NvBufSurface *inter_buf; + +#ifdef WITH_OPENCV + // OpenCV mat containing RGB data + cv::Mat *cvmat; +#endif + + // Input video info (resolution, color format, framerate, etc) + GstVideoInfo video_info; + + // Resolution at which frames/objects should be processed + gint processing_width; + gint processing_height; + + // Flag which defince igpu/dgpu + guint is_integrated; + + // Amount of objects processed in single call to algorithm + guint batch_size; + + // GPU ID on which we expect to execute the task + guint gpu_id; + + // Boolean indicating if entire frame or cropped objects should be processed + gboolean process_full_frame; + + // Boolean indicating if to blur the detected objects + gboolean blur_objects; +}; + +// Boiler plate stuff +struct _GstDsExampleClass +{ + GstBaseTransformClass parent_class; +}; + +GType gst_dsexample_get_type (void); + +G_END_DECLS +#endif /* __GST_DSEXAMPLE_H__ */ diff --git a/gstdsexample.o b/gstdsexample.o new file mode 100644 index 0000000..c5773ee Binary files /dev/null and b/gstdsexample.o differ diff --git a/gstdsexample_optimized.cpp b/gstdsexample_optimized.cpp new file mode 100755 index 0000000..ce07d07 --- /dev/null +++ b/gstdsexample_optimized.cpp @@ -0,0 +1,1301 @@ +/** + * Copyright (c) 2020-2021, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * There are two threads in the optimized code. input thread and Processing thread. + * The pre-procesing as required by the algorithm like scaling and color + * conversion of data is done in input thread. This is done using NvBufSurfTransform's + * batch conversion APIs to improve performance. The processing of data using custom + * algorithm and parsing the output and metadata attachment is done in separate processing + * thread. + * + * There are two queues used for buffering and transferring data between thread: + * Process_queue and buf_queue Process_queue is used to send filled batched data to + * process thread and buf_queue is used to get return empty processed buffers from + * process thread to input thread. Two buffers are used in a ping pong manner between + * the two threads for parallel processing. + */ + +#include +#include +#include +#include +#include +#include + +#include "gstdsexample_optimized.h" + +#include +#include +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_dsexample_debug); +#define GST_CAT_DEFAULT gst_dsexample_debug +#define USE_EGLIMAGE 1 + +#ifdef WITH_OPENCV +//enable to write transformed cvmat to files +//#define DSEXAMPLE_DEBUG +#ifdef DSEXAMPLE_DEBUG +#include "opencv2/imgcodecs.hpp" +#endif +#endif + +static GQuark _dsmeta_quark = 0; + +/* Enum to identify properties */ +enum +{ + PROP_0, + PROP_UNIQUE_ID, + PROP_PROCESSING_WIDTH, + PROP_PROCESSING_HEIGHT, + PROP_PROCESS_FULL_FRAME, + PROP_BATCH_SIZE, + PROP_GPU_DEVICE_ID +}; + +#define CHECK_NVDS_MEMORY_AND_GPUID(object, surface) \ + ({ int _errtype=0;\ + do { \ + if ((surface->memType == NVBUF_MEM_DEFAULT || surface->memType == NVBUF_MEM_CUDA_DEVICE) && \ + (surface->gpuId != object->gpu_id)) { \ + GST_ELEMENT_ERROR (object, RESOURCE, FAILED, \ + ("Input surface gpu-id doesnt match with configured gpu-id for element," \ + " please allocate input using unified memory, or use same gpu-ids"),\ + ("surface-gpu-id=%d,%s-gpu-id=%d",surface->gpuId,GST_ELEMENT_NAME(object),\ + object->gpu_id)); \ + _errtype = 1;\ + } \ + } while(0); \ + _errtype; \ + }) + + +/* Default values for properties */ +#define DEFAULT_UNIQUE_ID 15 +#define DEFAULT_PROCESSING_WIDTH 640 +#define DEFAULT_PROCESSING_HEIGHT 480 +#define DEFAULT_PROCESS_FULL_FRAME TRUE +#define DEFAULT_GPU_ID 0 +#define DEFAULT_BATCH_SIZE 1 + +#define RGB_BYTES_PER_PIXEL 3 +#define RGBA_BYTES_PER_PIXEL 4 +#define Y_BYTES_PER_PIXEL 1 +#define UV_BYTES_PER_PIXEL 2 + +#define MIN_INPUT_OBJECT_WIDTH 16 +#define MIN_INPUT_OBJECT_HEIGHT 16 + +#define CHECK_NPP_STATUS(npp_status,error_str) do { \ + if ((npp_status) != NPP_SUCCESS) { \ + g_print ("Error: %s in %s at line %d: NPP Error %d\n", \ + error_str, __FILE__, __LINE__, npp_status); \ + goto error; \ + } \ +} while (0) + +#define CHECK_CUDA_STATUS(cuda_status,error_str) do { \ + if ((cuda_status) != cudaSuccess) { \ + g_print ("Error: %s in %s at line %d (%s)\n", \ + error_str, __FILE__, __LINE__, cudaGetErrorName(cuda_status)); \ + goto error; \ + } \ +} while (0) + +/* By default NVIDIA Hardware allocated memory flows through the pipeline. We + * will be processing on this type of memory only. */ +#define GST_CAPS_FEATURE_MEMORY_NVMM "memory:NVMM" +static GstStaticPadTemplate gst_dsexample_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES + (GST_CAPS_FEATURE_MEMORY_NVMM, + "{ NV12, RGBA, I420 }"))); + +static GstStaticPadTemplate gst_dsexample_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES + (GST_CAPS_FEATURE_MEMORY_NVMM, + "{ NV12, RGBA, I420 }"))); + +/* Define our element type. Standard GObject/GStreamer boilerplate stuff */ +#define gst_dsexample_parent_class parent_class +G_DEFINE_TYPE (GstDsExample, gst_dsexample, GST_TYPE_BASE_TRANSFORM); + +static void gst_dsexample_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_dsexample_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_dsexample_set_caps (GstBaseTransform * btrans, + GstCaps * incaps, GstCaps * outcaps); +static gboolean gst_dsexample_start (GstBaseTransform * btrans); +static gboolean gst_dsexample_stop (GstBaseTransform * btrans); + +static GstFlowReturn +gst_dsexample_submit_input_buffer (GstBaseTransform * btrans, + gboolean discont, GstBuffer * inbuf); +static GstFlowReturn +gst_dsexample_generate_output (GstBaseTransform * btrans, GstBuffer ** outbuf); + +static void +attach_metadata_full_frame (GstDsExample * dsexample, + NvDsFrameMeta * frame_meta, gdouble scale_ratio, DsExampleOutput * output, + guint batch_id); +static void attach_metadata_object (GstDsExample * dsexample, + NvDsObjectMeta * obj_meta, DsExampleOutput * output); + +static gpointer gst_dsexample_output_loop (gpointer data); + +/* Install properties, set sink and src pad capabilities, override the required + * functions of the base class, These are common to all instances of the + * element. + */ +static void +gst_dsexample_class_init (GstDsExampleClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseTransformClass *gstbasetransform_class; + + // Indicates we want to use DS buf api + g_setenv ("DS_NEW_BUFAPI", "1", TRUE); + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasetransform_class = (GstBaseTransformClass *) klass; + + /* Overide base class functions */ + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_dsexample_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_dsexample_get_property); + + gstbasetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_dsexample_set_caps); + gstbasetransform_class->start = GST_DEBUG_FUNCPTR (gst_dsexample_start); + gstbasetransform_class->stop = GST_DEBUG_FUNCPTR (gst_dsexample_stop); + + gstbasetransform_class->submit_input_buffer = + GST_DEBUG_FUNCPTR (gst_dsexample_submit_input_buffer); + gstbasetransform_class->generate_output = + GST_DEBUG_FUNCPTR (gst_dsexample_generate_output); + + /* Install properties */ + g_object_class_install_property (gobject_class, PROP_UNIQUE_ID, + g_param_spec_uint ("unique-id", + "Unique ID", + "Unique ID for the element. Can be used to identify output of the" + " element", 0, G_MAXUINT, DEFAULT_UNIQUE_ID, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_PROCESSING_WIDTH, + g_param_spec_int ("processing-width", + "Processing Width", + "Width of the input buffer to algorithm", + 1, G_MAXINT, DEFAULT_PROCESSING_WIDTH, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_PROCESSING_HEIGHT, + g_param_spec_int ("processing-height", + "Processing Height", + "Height of the input buffer to algorithm", + 1, G_MAXINT, DEFAULT_PROCESSING_HEIGHT, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_PROCESS_FULL_FRAME, + g_param_spec_boolean ("full-frame", + "Full frame", + "Enable to process full frame or disable to process objects detected" + "by primary detector", DEFAULT_PROCESS_FULL_FRAME, (GParamFlags) + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_BATCH_SIZE, + g_param_spec_uint ("batch-size", "Batch Size", + "Maximum batch size for processing", + 1, NVDSEXAMPLE_MAX_BATCH_SIZE, DEFAULT_BATCH_SIZE, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + + g_object_class_install_property (gobject_class, PROP_GPU_DEVICE_ID, + g_param_spec_uint ("gpu-id", + "Set GPU Device ID", + "Set GPU Device ID", 0, + G_MAXUINT, 0, + GParamFlags + (G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY))); + /* Set sink and src pad capabilities */ + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_dsexample_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_dsexample_sink_template)); + + /* Set metadata describing the element */ + gst_element_class_set_details_simple (gstelement_class, + "DsExample plugin", + "DsExample Plugin", + "Process a 3rdparty example algorithm on objects / full frame", + "NVIDIA Corporation. Post on Deepstream for Tesla forum for any queries " + "@ https://devtalk.nvidia.com/default/board/209/"); +} + +static void +gst_dsexample_init (GstDsExample * dsexample) +{ + GstBaseTransform *btrans = GST_BASE_TRANSFORM (dsexample); + + /* We will not be generating a new buffer. Just adding / updating + * metadata. */ + gst_base_transform_set_in_place (GST_BASE_TRANSFORM (btrans), TRUE); + /* We do not want to change the input caps. Set to passthrough. transform_ip + * is still called. */ + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (btrans), TRUE); + + /* Initialize all property variables to default values */ + dsexample->unique_id = DEFAULT_UNIQUE_ID; + dsexample->processing_width = DEFAULT_PROCESSING_WIDTH; + dsexample->processing_height = DEFAULT_PROCESSING_HEIGHT; + dsexample->process_full_frame = DEFAULT_PROCESS_FULL_FRAME; + dsexample->gpu_id = DEFAULT_GPU_ID; + dsexample->max_batch_size = DEFAULT_BATCH_SIZE; + /* This quark is required to identify NvDsMeta when iterating through + * the buffer metadatas */ + if (!_dsmeta_quark) + _dsmeta_quark = g_quark_from_static_string (NVDS_META_STRING); +} + +/* Function called when a property of the element is set. Standard boilerplate. + */ +static void +gst_dsexample_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (object); + switch (prop_id) { + case PROP_UNIQUE_ID: + dsexample->unique_id = g_value_get_uint (value); + break; + case PROP_PROCESSING_WIDTH: + dsexample->processing_width = g_value_get_int (value); + break; + case PROP_PROCESSING_HEIGHT: + dsexample->processing_height = g_value_get_int (value); + break; + case PROP_PROCESS_FULL_FRAME: + dsexample->process_full_frame = g_value_get_boolean (value); + break; + case PROP_GPU_DEVICE_ID: + dsexample->gpu_id = g_value_get_uint (value); + break; + case PROP_BATCH_SIZE: + dsexample->max_batch_size = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* Function called when a property of the element is requested. Standard + * boilerplate. + */ +static void +gst_dsexample_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (object); + + switch (prop_id) { + case PROP_UNIQUE_ID: + g_value_set_uint (value, dsexample->unique_id); + break; + case PROP_PROCESSING_WIDTH: + g_value_set_int (value, dsexample->processing_width); + break; + case PROP_PROCESSING_HEIGHT: + g_value_set_int (value, dsexample->processing_height); + break; + case PROP_PROCESS_FULL_FRAME: + g_value_set_boolean (value, dsexample->process_full_frame); + break; + case PROP_GPU_DEVICE_ID: + g_value_set_uint (value, dsexample->gpu_id); + break; + case PROP_BATCH_SIZE: + g_value_set_uint (value, dsexample->max_batch_size); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * Initialize all resources and start the process thread + */ +static gboolean +gst_dsexample_start (GstBaseTransform * btrans) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + std::string nvtx_str; +#ifdef WITH_OPENCV + // OpenCV mat containing RGB data + cv::Mat * cvmat; +#else + NvBufSurface * inter_buf; +#endif + NvBufSurfaceCreateParams create_params; + DsExampleInitParams init_params = + { dsexample->processing_width, dsexample->processing_height, + dsexample->process_full_frame }; + + /* Algorithm specific initializations and resource allocation. */ + dsexample->dsexamplelib_ctx = DsExampleCtxInit (&init_params); + + GST_DEBUG_OBJECT (dsexample, "ctx lib %p \n", dsexample->dsexamplelib_ctx); + + nvtx_str = "GstNvDsExample: UID=" + std::to_string(dsexample->unique_id); + auto nvtx_deleter = [](nvtxDomainHandle_t d) { nvtxDomainDestroy (d); }; + std::unique_ptr nvtx_domain_ptr ( + nvtxDomainCreate(nvtx_str.c_str()), nvtx_deleter); + + CHECK_CUDA_STATUS (cudaSetDevice (dsexample->gpu_id), + "Unable to set cuda device"); + + CHECK_CUDA_STATUS (cudaStreamCreate (&dsexample->cuda_stream), + "Could not create cuda stream"); + +#ifdef WITH_OPENCV + if (dsexample->inter_buf) + NvBufSurfaceDestroy (dsexample->inter_buf); + dsexample->inter_buf = NULL; +#endif + + /* An intermediate buffer for NV12/RGBA to BGR conversion will be + * required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */ + create_params.gpuId = dsexample->gpu_id; + create_params.width = dsexample->processing_width; + create_params.height = dsexample->processing_height; + create_params.size = 0; + create_params.colorFormat = NVBUF_COLOR_FORMAT_RGBA; + create_params.layout = NVBUF_LAYOUT_PITCH; +#ifdef __aarch64__ + create_params.memType = NVBUF_MEM_DEFAULT; +#else + create_params.memType = NVBUF_MEM_CUDA_UNIFIED; +#endif + +#ifdef WITH_OPENCV + if (NvBufSurfaceCreate (&dsexample->inter_buf, dsexample->max_batch_size, + &create_params) != 0) { + GST_ERROR ("Error: Could not allocate internal buffer for dsexample"); + goto error; + } +#endif + + /* Create process queue and cvmat queue to transfer data between threads. + * We will be using this queue to maintain the list of frames/objects + * currently given to the algorithm for processing. */ + dsexample->process_queue = g_queue_new (); + dsexample->buf_queue = g_queue_new (); + +#ifdef WITH_OPENCV + /* Push cvmat buffer twice on the buf_queue which will handle the + * different processing speed between input thread and process thread + * cvmat queue is used for getting processed data from the process thread*/ + for (int i = 0; i < 2; i++) { + // CV Mat containing interleaved RGB data. + cvmat = new cv::Mat[dsexample->max_batch_size]; + + for (guint j = 0; j < dsexample->max_batch_size; j++) { + cvmat[j] = + cv::Mat (dsexample->processing_height, dsexample->processing_width, + CV_8UC3); + } + + if (!cvmat) + goto error; + + g_queue_push_tail (dsexample->buf_queue, cvmat); + } + + GST_DEBUG_OBJECT (dsexample, "created CV Mat\n"); +#else + for (int i = 0; i < 2; i++) { + if (NvBufSurfaceCreate (&inter_buf, dsexample->max_batch_size, + &create_params) != 0) { + GST_ERROR ("Error: Could not allocate internal buffer for dsexample"); + goto error; + } + + g_queue_push_tail (dsexample->buf_queue, inter_buf); + } +#endif + + /* Set the NvBufSurfTransform config parameters. */ + dsexample->transform_config_params.compute_mode = + NvBufSurfTransformCompute_Default; + dsexample->transform_config_params.gpu_id = dsexample->gpu_id; + + /* Create the intermediate NvBufSurface structure for holding an array of input + * NvBufSurfaceParams for batched transforms. */ + dsexample->batch_insurf.surfaceList = + new NvBufSurfaceParams[dsexample->max_batch_size]; + dsexample->batch_insurf.batchSize = dsexample->max_batch_size; + dsexample->batch_insurf.gpuId = dsexample->gpu_id; + + /* Set up the NvBufSurfTransformParams structure for batched transforms. */ + dsexample->transform_params.src_rect = + new NvBufSurfTransformRect[dsexample->max_batch_size]; + dsexample->transform_params.dst_rect = + new NvBufSurfTransformRect[dsexample->max_batch_size]; + dsexample->transform_params.transform_flag = + NVBUFSURF_TRANSFORM_FILTER | NVBUFSURF_TRANSFORM_CROP_SRC | + NVBUFSURF_TRANSFORM_CROP_DST; + dsexample->transform_params.transform_flip = NvBufSurfTransform_None; + dsexample->transform_params.transform_filter = + NvBufSurfTransformInter_Default; + + /* Start a thread which will pop output from the algorithm, form NvDsMeta and + * push buffers to the next element. */ + dsexample->process_thread = + g_thread_new ("dsexample-process-thread", gst_dsexample_output_loop, + dsexample); + + dsexample->nvtx_domain = nvtx_domain_ptr.release (); + + return TRUE; +error: + + delete[]dsexample->transform_params.src_rect; + delete[]dsexample->transform_params.dst_rect; + delete[]dsexample->batch_insurf.surfaceList; + + if (dsexample->cuda_stream) { + cudaStreamDestroy (dsexample->cuda_stream); + dsexample->cuda_stream = NULL; + } + if (dsexample->dsexamplelib_ctx) + DsExampleCtxDeinit (dsexample->dsexamplelib_ctx); + return FALSE; +} + +/** + * Stop the process thread and free up all the resources + */ +static gboolean +gst_dsexample_stop (GstBaseTransform * btrans) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + +#ifdef WITH_OPENCV + cv::Mat * cvmat; +#else + NvBufSurface * inter_buf; +#endif + + g_mutex_lock (&dsexample->process_lock); + + /* Wait till all the items in the queue are handled. */ + while (!g_queue_is_empty (dsexample->process_queue)) { + g_cond_wait (&dsexample->process_cond, &dsexample->process_lock); + } + +#ifdef WITH_OPENCV + while (!g_queue_is_empty (dsexample->buf_queue)) { + cvmat = (cv::Mat *) g_queue_pop_head (dsexample->buf_queue); + delete[]cvmat; + cvmat = NULL; + } +#else + while (!g_queue_is_empty (dsexample->buf_queue)) { + inter_buf = (NvBufSurface *) g_queue_pop_head (dsexample->buf_queue); + if (inter_buf) + NvBufSurfaceDestroy (inter_buf); + inter_buf = NULL; + } +#endif + dsexample->stop = TRUE; + + g_cond_broadcast (&dsexample->process_cond); + g_mutex_unlock (&dsexample->process_lock); + + g_thread_join (dsexample->process_thread); + +#ifdef WITH_OPENCV + if (dsexample->inter_buf) + NvBufSurfaceDestroy (dsexample->inter_buf); + dsexample->inter_buf = NULL; +#endif + + if (dsexample->cuda_stream) + cudaStreamDestroy (dsexample->cuda_stream); + dsexample->cuda_stream = NULL; + + delete[]dsexample->transform_params.src_rect; + delete[]dsexample->transform_params.dst_rect; + delete[]dsexample->batch_insurf.surfaceList; + +#ifdef WITH_OPENCV + GST_DEBUG_OBJECT (dsexample, "deleted CV Mat \n"); +#endif + + // Deinit the algorithm library + DsExampleCtxDeinit (dsexample->dsexamplelib_ctx); + dsexample->dsexamplelib_ctx = NULL; + + GST_DEBUG_OBJECT (dsexample, "ctx lib released \n"); + + g_queue_free (dsexample->process_queue); + + g_queue_free (dsexample->buf_queue); + + return TRUE; +} + +/** + * Called when source / sink pad capabilities have been negotiated. + */ +static gboolean +gst_dsexample_set_caps (GstBaseTransform * btrans, GstCaps * incaps, + GstCaps * outcaps) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + /* Save the input video information, since this will be required later. */ + gst_video_info_from_caps (&dsexample->video_info, incaps); + + CHECK_CUDA_STATUS (cudaSetDevice (dsexample->gpu_id), + "Unable to set cuda device"); + + return TRUE; + +error: + return FALSE; +} + +/** + * Scale the entire frame to the processing resolution maintaining aspect ratio. + * Or crop and scale objects to the processing resolution maintaining the aspect + * ratio and fills data for batched conversation */ +static GstFlowReturn +scale_and_fill_data(GstDsExample * dsexample, + NvBufSurfaceParams * src_frame, NvOSD_RectParams * crop_rect_params, + gdouble & ratio, gint input_width, gint input_height) +{ + + gint src_left = GST_ROUND_UP_2((unsigned int)crop_rect_params->left); + gint src_top = GST_ROUND_UP_2((unsigned int)crop_rect_params->top); + gint src_width = GST_ROUND_DOWN_2((unsigned int)crop_rect_params->width); + gint src_height = GST_ROUND_DOWN_2((unsigned int)crop_rect_params->height); + + // Maintain aspect ratio + double hdest = dsexample->processing_width * src_height / (double) src_width; + double wdest = dsexample->processing_height * src_width / (double) src_height; + guint dest_width, dest_height; + + if (hdest <= dsexample->processing_height) { + dest_width = dsexample->processing_width; + dest_height = hdest; + } else { + dest_width = wdest; + dest_height = dsexample->processing_height; + } + + // Calculate scaling ratio while maintaining aspect ratio + ratio = MIN (1.0 * dest_width / src_width, 1.0 * dest_height / src_height); + + if ((crop_rect_params->width == 0) || (crop_rect_params->height == 0)) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:crop_rect_params dimensions are zero", __func__), (NULL)); + return GST_FLOW_ERROR; + } +#ifdef __aarch64__ + if (ratio <= 1.0 / 16 || ratio >= 16.0) { + // Currently cannot scale by ratio > 16 or < 1/16 for Jetson + return GST_FLOW_ERROR; + } +#endif + + /* We will first convert only the Region of Interest (the entire frame or the + * object bounding box) to RGB and then scale the converted RGB frame to + * processing resolution. */ + GST_DEBUG_OBJECT (dsexample, "Scaling and converting input buffer\n"); + + /* Create temporary src and dest surfaces for NvBufSurfTransform API. */ + dsexample->batch_insurf.surfaceList[dsexample->batch_insurf.numFilled] = *src_frame; + + /* Set the source ROI. Could be entire frame or an object. */ + dsexample->transform_params.src_rect[dsexample->batch_insurf.numFilled] = { + (guint) src_top, (guint) src_left, (guint) src_width, (guint) src_height}; + /* Set the dest ROI. Could be the entire destination frame or part of it to + * maintain aspect ratio. */ + dsexample->transform_params.dst_rect[dsexample->batch_insurf.numFilled] = { + 0, 0, dest_width, dest_height}; + + dsexample->batch_insurf.numFilled++; + + return GST_FLOW_OK; +} + +static gboolean +convert_batch_and_push_to_process_thread (GstDsExample * dsexample, + GstDsExampleBatch * batch) +{ + + NvBufSurfTransform_Error err; + NvBufSurfTransformConfigParams transform_config_params; + std::string nvtx_str; +#ifdef WITH_OPENCV + cv::Mat in_mat; +#endif + + // Configure transform session parameters for the transformation + transform_config_params.compute_mode = NvBufSurfTransformCompute_Default; + transform_config_params.gpu_id = dsexample->gpu_id; + transform_config_params.cuda_stream = dsexample->cuda_stream; + + err = NvBufSurfTransformSetSessionParams (&transform_config_params); + if (err != NvBufSurfTransformError_Success) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("NvBufSurfTransformSetSessionParams failed with error %d", err), + (NULL)); + return FALSE; + } + + nvtxEventAttributes_t eventAttrib = {0}; + eventAttrib.version = NVTX_VERSION; + eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; + eventAttrib.colorType = NVTX_COLOR_ARGB; + eventAttrib.color = 0xFFFF0000; + eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; + nvtx_str = "convert_buf batch_num=" + std::to_string(dsexample->current_batch_num); + eventAttrib.message.ascii = nvtx_str.c_str(); + + nvtxDomainRangePushEx(dsexample->nvtx_domain, &eventAttrib); + + g_mutex_lock (&dsexample->process_lock); + + /* Wait if buf queue is empty. */ + while (g_queue_is_empty (dsexample->buf_queue)) { + g_cond_wait (&dsexample->buf_cond, &dsexample->process_lock); + } + +#ifdef WITH_OPENCV + /* Pop a buffer from the element's buf queue. */ + batch->cvmat = (cv::Mat *) g_queue_pop_head (dsexample->buf_queue); +#else + /* Pop a buffer from the element's buf queue. */ + batch->inter_buf = (NvBufSurface *) g_queue_pop_head (dsexample->buf_queue); + dsexample->inter_buf = batch->inter_buf; +#endif + + g_mutex_unlock (&dsexample->process_lock); + + //Memset the memory + for (uint i = 0; i < dsexample->batch_insurf.numFilled; i++) + NvBufSurfaceMemSet (dsexample->inter_buf, i, 0, 0); + + /* Batched tranformation. */ + err = NvBufSurfTransform (&dsexample->batch_insurf, dsexample->inter_buf, + &dsexample->transform_params); + + nvtxDomainRangePop (dsexample->nvtx_domain); + + if (err != NvBufSurfTransformError_Success) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("NvBufSurfTransform failed with error %d while converting buffer", + err), (NULL)); + return FALSE; + } + + // Use openCV to remove padding and convert RGBA to BGR. Can be skipped if + // algorithm can handle padded RGBA data. + for (guint i = 0; i < dsexample->batch_insurf.numFilled; i++) { + // Map the buffer so that it can be accessed by CPU + if (NvBufSurfaceMap (dsexample->inter_buf, i, 0, NVBUF_MAP_READ) != 0) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:buffer map to be accessed by CPU failed", __func__), (NULL)); + return FALSE; + } + // sync mapped data for CPU access + NvBufSurfaceSyncForCpu (dsexample->inter_buf, i,0); + +#ifdef WITH_OPENCV + in_mat = + cv::Mat (dsexample->processing_height, dsexample->processing_width, + CV_8UC4,dsexample->inter_buf->surfaceList[i].mappedAddr.addr[0], + dsexample->inter_buf->surfaceList[i].pitch); + +#if (CV_MAJOR_VERSION >= 4) + cv::cvtColor (in_mat, batch->cvmat[i], cv::COLOR_RGBA2BGR); +#else + cv::cvtColor (in_mat, batch->cvmat[i], CV_RGBA2BGR); +#endif + +#ifdef DSEXAMPLE_DEBUG + static guint cnt = 0; + cv::imwrite("out_" + std::to_string (cnt) + ".jpeg", batch->cvmat[i]); + cnt++; +#endif +#endif + + if (NvBufSurfaceUnMap (dsexample->inter_buf, i,0)) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:buffer unmap to be accessed by CPU failed", __func__), (NULL)); + return FALSE; + } + +#ifdef __aarch64__ + // To use the converted buffer in CUDA, create an EGLImage and then use + // CUDA-EGL interop APIs + if (USE_EGLIMAGE) { + if (NvBufSurfaceMapEglImage (dsexample->inter_buf, 0) != 0) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:buffer map eglimage failed", __func__), (NULL)); + return FALSE; + } + // dsexample->inter_buf->surfaceList[0].mappedAddr.eglImage + // Use interop APIs cuGraphicsEGLRegisterImage and + // cuGraphicsResourceGetMappedEglFrame to access the buffer in CUDA + + // Destroy the EGLImage + NvBufSurfaceUnMapEglImage (dsexample->inter_buf, 0); + } +#endif + } + + /* Push the batch info structure in the processing queue and notify the process + * thread that a new batch has been queued. */ + g_mutex_lock (&dsexample->process_lock); + + g_queue_push_tail (dsexample->process_queue, batch); + g_cond_broadcast (&dsexample->process_cond); + + g_mutex_unlock (&dsexample->process_lock); + + return TRUE; +} + +/** + * Called when element recieves an input buffer from upstream element. + */ +static GstFlowReturn +gst_dsexample_submit_input_buffer (GstBaseTransform * btrans, + gboolean discont, GstBuffer * inbuf) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + GstMapInfo in_map_info; + NvBufSurface *in_surf; + GstDsExampleBatch *buf_push_batch; + GstFlowReturn flow_ret; + std::string nvtx_str; + std::unique_ptr < GstDsExampleBatch > batch = nullptr; + + NvDsBatchMeta *batch_meta = NULL; + guint i = 0; + gdouble scale_ratio = 1.0; + guint num_filled = 0; + + dsexample->current_batch_num++; + + nvtxEventAttributes_t eventAttrib = {0}; + eventAttrib.version = NVTX_VERSION; + eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; + eventAttrib.colorType = NVTX_COLOR_ARGB; + eventAttrib.color = 0xFFFF0000; + eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; + nvtx_str = "buffer_process batch_num=" + std::to_string(dsexample->current_batch_num); + eventAttrib.message.ascii = nvtx_str.c_str(); + nvtxRangeId_t buf_process_range = nvtxDomainRangeStartEx(dsexample->nvtx_domain, &eventAttrib); + + memset (&in_map_info, 0, sizeof (in_map_info)); + + /* Map the buffer contents and get the pointer to NvBufSurface. */ + if (!gst_buffer_map (inbuf, &in_map_info, GST_MAP_READ)) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("%s:gst buffer map to get pointer to NvBufSurface failed", __func__), (NULL)); + return GST_FLOW_ERROR; + } + in_surf = (NvBufSurface *) in_map_info.data; + + nvds_set_input_system_timestamp (inbuf, GST_ELEMENT_NAME (dsexample)); + + batch_meta = gst_buffer_get_nvds_batch_meta (inbuf); + if (batch_meta == nullptr) { + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("NvDsBatchMeta not found for input buffer."), (NULL)); + return GST_FLOW_ERROR; + } + num_filled = batch_meta->num_frames_in_batch; + + if (dsexample->process_full_frame) { + for (guint i = 0; i < num_filled; i++) { + NvOSD_RectParams rect_params; + + // Scale the entire frame to processing resolution + rect_params.left = 0; + rect_params.top = 0; + rect_params.width = in_surf->surfaceList[i].width; + rect_params.height = in_surf->surfaceList[i].height; + + // Scale the frame maintaining aspect ratio + if (scale_and_fill_data (dsexample, in_surf->surfaceList + i, + &rect_params, scale_ratio, dsexample->video_info.width, + dsexample->video_info.height) != GST_FLOW_OK) { + goto error; + } + + if (batch == nullptr) { + batch.reset (new GstDsExampleBatch); + batch->push_buffer = FALSE; + batch->inbuf = inbuf; + batch->inbuf_batch_num = dsexample->current_batch_num; + } + + /* Adding a frame to the current batch. Set the frames members. */ + GstDsExampleFrame frame; + frame.scale_ratio_x = scale_ratio; + frame.scale_ratio_y = scale_ratio; + frame.obj_meta = nullptr; + frame.frame_meta = + nvds_get_nth_frame_meta (batch_meta->frame_meta_list, i); + frame.frame_num = frame.frame_meta->frame_num; + frame.batch_index = i; + frame.input_surf_params = in_surf->surfaceList + i; + batch->frames.push_back (frame); + + // Set the transform session parameters for the conversions executed in this + // thread. + if (batch->frames.size () == dsexample->max_batch_size || i == num_filled) { + if (!convert_batch_and_push_to_process_thread (dsexample, batch.get ())) { + return GST_FLOW_ERROR; + } + /* Batch submitted. Set batch to nullptr so that a new GstDsExampleBatch + * structure can be allocated if required. */ + batch.release (); + dsexample->batch_insurf.numFilled = 0; + } + } + } else { + // Using object crops as input to the algorithm. The objects are detected by + // the primary detector + NvDsFrameMeta *frame_meta = NULL; + NvDsMetaList *l_frame = NULL; + NvDsObjectMeta *obj_meta = NULL; + NvDsMetaList *l_obj = NULL; + + for (l_frame = batch_meta->frame_meta_list; l_frame != NULL; + l_frame = l_frame->next) { + frame_meta = (NvDsFrameMeta *) (l_frame->data); + for (l_obj = frame_meta->obj_meta_list; l_obj != NULL; + l_obj = l_obj->next) { + obj_meta = (NvDsObjectMeta *) (l_obj->data); + + /* Should not process on objects smaller than MIN_INPUT_OBJECT_WIDTH x MIN_INPUT_OBJECT_HEIGHT + * since it will cause hardware scaling issues. */ + if (obj_meta->rect_params.width < MIN_INPUT_OBJECT_WIDTH || + obj_meta->rect_params.height < MIN_INPUT_OBJECT_HEIGHT) + continue; + + // Crop and scale the object maintainig aspect ratio + if (scale_and_fill_data (dsexample, + in_surf->surfaceList + frame_meta->batch_id, + &obj_meta->rect_params, scale_ratio, + dsexample->video_info.width, + dsexample->video_info.height) != GST_FLOW_OK) { + // Error in conversion, skip processing on object. */ + continue; + } + + if (batch == nullptr) { + batch.reset (new GstDsExampleBatch); + batch->push_buffer = FALSE; + batch->inbuf = inbuf; + batch->inbuf_batch_num = dsexample->current_batch_num; + batch->nvtx_complete_buf_range = buf_process_range; + } + + /* Adding a frame to the current batch. Set the frames members. */ + GstDsExampleFrame frame; + frame.scale_ratio_x = scale_ratio; + frame.scale_ratio_y = scale_ratio; + frame.obj_meta = obj_meta; + frame.frame_meta = + nvds_get_nth_frame_meta (batch_meta->frame_meta_list, i); + frame.frame_num = frame.frame_meta->frame_num; + frame.batch_index = i; + frame.input_surf_params = in_surf->surfaceList + i; + batch->frames.push_back (frame); + + i++; + + // Convert batch and push to process thread + if (batch->frames.size () == dsexample->max_batch_size + || i == num_filled) { + if (!convert_batch_and_push_to_process_thread (dsexample, + batch.get ())) { + return GST_FLOW_ERROR; + } + /* Batch submitted. Set batch to nullptr so that a new GstDsExampleBatch + * structure can be allocated if required. */ + i = 0; + batch.release (); + dsexample->batch_insurf.numFilled = 0; + } + } + } + } + /* Submit a non-full batch. */ + if (batch) { + if (!convert_batch_and_push_to_process_thread (dsexample, batch.get ())) { + return GST_FLOW_ERROR; + } + batch.release (); + dsexample->batch_insurf.numFilled = 0; + } + + nvtxDomainRangeEnd(dsexample->nvtx_domain, buf_process_range); + + /* Queue a push buffer batch. This batch is not inferred. This batch is to + * signal the process thread that there are no more batches + * belonging to this input buffer and this GstBuffer can be pushed to + * downstream element once all the previous processing is done. */ + buf_push_batch = new GstDsExampleBatch; + buf_push_batch->inbuf = inbuf; + buf_push_batch->push_buffer = TRUE; + buf_push_batch->nvtx_complete_buf_range = buf_process_range; + + g_mutex_lock (&dsexample->process_lock); + /* Check if this is a push buffer or event marker batch. If yes, no need to + * queue the input for inferencing. */ + if (buf_push_batch->push_buffer) { + /* Push the batch info structure in the processing queue and notify the + * process thread that a new batch has been queued. */ + g_queue_push_tail (dsexample->process_queue, buf_push_batch); + g_cond_broadcast (&dsexample->process_cond); + } + g_mutex_unlock (&dsexample->process_lock); + + flow_ret = GST_FLOW_OK; + +error: + gst_buffer_unmap (inbuf, &in_map_info); + return flow_ret; +} + +/** + * If submit_input_buffer is implemented, it is mandatory to implement + * generate_output. Buffers are not pushed to the downstream element from here. + * Return the GstFlowReturn value of the latest pad push so that any error might + * be caught by the application. + */ +static GstFlowReturn +gst_dsexample_generate_output (GstBaseTransform * btrans, GstBuffer ** outbuf) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (btrans); + return dsexample->last_flow_ret; +} + +/** + * Attach metadata for the full frame. We will be adding a new metadata. + */ +static void +attach_metadata_full_frame (GstDsExample * dsexample, + NvDsFrameMeta * frame_meta, gdouble scale_ratio, DsExampleOutput * output, + guint batch_id) +{ + NvDsBatchMeta *batch_meta = frame_meta->base_meta.batch_meta; + NvDsObjectMeta *object_meta = NULL; + static gchar font_name[] = "Serif"; + GST_DEBUG_OBJECT (dsexample, "Attaching metadata %d\n", output->numObjects); + + for (gint i = 0; i < output->numObjects; i++) { + DsExampleObject *obj = &output->object[i]; + object_meta = nvds_acquire_obj_meta_from_pool (batch_meta); + NvOSD_RectParams & rect_params = object_meta->rect_params; + NvOSD_TextParams & text_params = object_meta->text_params; + + // Assign bounding box coordinates + rect_params.left = obj->left; + rect_params.top = obj->top; + rect_params.width = obj->width; + rect_params.height = obj->height; + + // Semi-transparent yellow background + rect_params.has_bg_color = 0; + rect_params.bg_color = (NvOSD_ColorParams) { + 1, 1, 0, 0.4}; + // Red border of width 6 + rect_params.border_width = 3; + rect_params.border_color = (NvOSD_ColorParams) { + 1, 0, 0, 1}; + + // Scale the bounding boxes proportionally based on how the object/frame was + // scaled during input + rect_params.left /= scale_ratio; + rect_params.top /= scale_ratio; + rect_params.width /= scale_ratio; + rect_params.height /= scale_ratio; + GST_DEBUG_OBJECT (dsexample, "Attaching rect%d of batch%u" + " left->%f top->%f width->%f" + " height->%f label->%s\n", i, batch_id, rect_params.left, + rect_params.top, rect_params.width, rect_params.height, obj->label); + + object_meta->object_id = UNTRACKED_OBJECT_ID; + g_strlcpy (object_meta->obj_label, obj->label, MAX_LABEL_SIZE); + // display_text required heap allocated memory + text_params.display_text = g_strdup (obj->label); + // Display text above the left top corner of the object + text_params.x_offset = rect_params.left; + text_params.y_offset = rect_params.top - 10; + // Set black background for the text + text_params.set_bg_clr = 1; + text_params.text_bg_clr = (NvOSD_ColorParams) { + 0, 0, 0, 1}; + // Font face, size and color + text_params.font_params.font_name = font_name; + text_params.font_params.font_size = 11; + text_params.font_params.font_color = (NvOSD_ColorParams) { + 1, 1, 1, 1}; + + nvds_add_obj_meta_to_frame (frame_meta, object_meta, NULL); + } +} + +/** + * Only update string label in an existing object metadata. No bounding boxes. + * We assume only one label per object is generated + */ +static void +attach_metadata_object (GstDsExample * dsexample, NvDsObjectMeta * obj_meta, + DsExampleOutput * output) +{ + if (output->numObjects == 0) + return; + NvDsBatchMeta *batch_meta = obj_meta->base_meta.batch_meta; + + NvDsClassifierMeta *classifier_meta = + nvds_acquire_classifier_meta_from_pool (batch_meta); + + classifier_meta->unique_component_id = dsexample->unique_id; + + NvDsLabelInfo *label_info = + nvds_acquire_label_info_meta_from_pool (batch_meta); + g_strlcpy (label_info->result_label, output->object[0].label, MAX_LABEL_SIZE); + nvds_add_label_info_meta_to_classifier (classifier_meta, label_info); + nvds_add_classifier_meta_to_object (obj_meta, classifier_meta); + + nvds_acquire_meta_lock (batch_meta); + NvOSD_TextParams & text_params = obj_meta->text_params; + NvOSD_RectParams & rect_params = obj_meta->rect_params; + + /* Below code to display the result */ + // Set black background for the text + // display_text required heap allocated memory + if (text_params.display_text) { + gchar *conc_string = g_strconcat (text_params.display_text, " ", + output->object[0].label, NULL); + g_free (text_params.display_text); + text_params.display_text = conc_string; + } else { + // Display text above the left top corner of the object + text_params.x_offset = rect_params.left; + text_params.y_offset = rect_params.top - 10; + text_params.display_text = g_strdup (output->object[0].label); + // Font face, size and color + text_params.font_params.font_name = (char *) "Serif"; + text_params.font_params.font_size = 11; + text_params.font_params.font_color = (NvOSD_ColorParams) { + 1, 1, 1, 1}; + // Set black background for the text + text_params.set_bg_clr = 1; + text_params.text_bg_clr = (NvOSD_ColorParams) { + 0, 0, 0, 1}; + } + nvds_release_meta_lock (batch_meta); +} + +/** + * Output loop used to pop output from processing thread, attach the output to the + * buffer in form of NvDsMeta and push the buffer to downstream element. + */ +static gpointer +gst_dsexample_output_loop (gpointer data) +{ + GstDsExample *dsexample = GST_DSEXAMPLE (data); + DsExampleOutput *output; + NvDsObjectMeta *obj_meta = NULL; + gdouble scale_ratio = 1.0; + + nvtxEventAttributes_t eventAttrib = {0}; + eventAttrib.version = NVTX_VERSION; + eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; + eventAttrib.colorType = NVTX_COLOR_ARGB; + eventAttrib.color = 0xFFFF0000; + eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; + std::string nvtx_str; + + nvtx_str = + "gst-dsexample_output-loop_uid=" + std::to_string (dsexample->unique_id); + + g_mutex_lock (&dsexample->process_lock); + + /* Run till signalled to stop. */ + while (!dsexample->stop) { + std::unique_ptr < GstDsExampleBatch > batch = nullptr; + + /* Wait if processing queue is empty. */ + if (g_queue_is_empty (dsexample->process_queue)) { + g_cond_wait (&dsexample->process_cond, &dsexample->process_lock); + continue; + } + + /* Pop a batch from the element's process queue. */ + batch.reset ((GstDsExampleBatch *) + g_queue_pop_head (dsexample->process_queue)); + g_cond_broadcast (&dsexample->process_cond); + + /* Event marker used for synchronization. No need to process further. */ + if (batch->event_marker) { + continue; + } + + g_mutex_unlock (&dsexample->process_lock); + + /* Need to only push buffer to downstream element. This batch was not + * actually submitted for inferencing. */ + if (batch->push_buffer) { + nvtxDomainRangeEnd(dsexample->nvtx_domain, batch->nvtx_complete_buf_range); + + nvds_set_output_system_timestamp (batch->inbuf, + GST_ELEMENT_NAME (dsexample)); + + GstFlowReturn flow_ret = + gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (dsexample), + batch->inbuf); + if (dsexample->last_flow_ret != flow_ret) { + switch (flow_ret) { + /* Signal the application for pad push errors by posting a error message + * on the pipeline bus. */ + case GST_FLOW_ERROR: + case GST_FLOW_NOT_LINKED: + case GST_FLOW_NOT_NEGOTIATED: + GST_ELEMENT_ERROR (dsexample, STREAM, FAILED, + ("Internal data stream error."), + ("streaming stopped, reason %s (%d)", + gst_flow_get_name (flow_ret), flow_ret)); + break; + default: + break; + } + } + dsexample->last_flow_ret = flow_ret; + g_mutex_lock (&dsexample->process_lock); + continue; + } + + nvtx_str = "dequeueOutputAndAttachMeta batch_num=" + std::to_string(batch->inbuf_batch_num); + eventAttrib.message.ascii = nvtx_str.c_str(); + nvtxDomainRangePushEx(dsexample->nvtx_domain, &eventAttrib); + + /* For each frame attach metadata output. */ + for (guint i = 0; i < batch->frames.size (); i++) { + if (dsexample->process_full_frame) { + // Process to get the output +#ifdef WITH_OPENCV + output = + DsExampleProcess (dsexample->dsexamplelib_ctx, + batch->cvmat[i].data); +#else + output = + DsExampleProcess (dsexample->dsexamplelib_ctx, + (unsigned char *)batch->inter_buf->surfaceList[i].mappedAddr.addr[0]); +#endif + // Attach the metadata for the full frame + attach_metadata_full_frame (dsexample, batch->frames[i].frame_meta, + scale_ratio, output, i); + free (output); + } else { + GstDsExampleFrame & frame = batch->frames[i]; + + obj_meta = frame.obj_meta; + + /* Should not process on objects smaller than MIN_INPUT_OBJECT_WIDTH x MIN_INPUT_OBJECT_HEIGHT + * since it will cause hardware scaling issues. */ + if (obj_meta->rect_params.width < MIN_INPUT_OBJECT_WIDTH || + obj_meta->rect_params.height < MIN_INPUT_OBJECT_HEIGHT) + continue; + + // Process the object crop to obtain label +#ifdef WITH_OPENCV + output = DsExampleProcess (dsexample->dsexamplelib_ctx, + batch->cvmat[i].data); +#else + output = DsExampleProcess (dsexample->dsexamplelib_ctx, + (unsigned char *)batch->inter_buf->surfaceList[i].mappedAddr.addr[0]); +#endif + + // Attach labels for the object + attach_metadata_object (dsexample, obj_meta, output); + + free (output); + } + } + + g_mutex_lock (&dsexample->process_lock); + +#ifdef WITH_OPENCV + g_queue_push_tail (dsexample->buf_queue, batch->cvmat); +#else + g_queue_push_tail (dsexample->buf_queue, batch->inter_buf); +#endif + g_cond_broadcast (&dsexample->buf_cond); + + nvtxDomainRangePop (dsexample->nvtx_domain); + } + g_mutex_unlock (&dsexample->process_lock); + + return nullptr; +} + +/** + * Boiler plate for registering a plugin and an element. + */ +static gboolean +dsexample_plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_dsexample_debug, "dsexample", 0, + "dsexample plugin"); + + return gst_element_register (plugin, "dsexample", GST_RANK_PRIMARY, + GST_TYPE_DSEXAMPLE); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + nvdsgst_dsexample, + DESCRIPTION, dsexample_plugin_init, "6.0", LICENSE, BINARY_PACKAGE, + URL) diff --git a/gstdsexample_optimized.h b/gstdsexample_optimized.h new file mode 100755 index 0000000..9f2bc33 --- /dev/null +++ b/gstdsexample_optimized.h @@ -0,0 +1,215 @@ +/** + * Copyright (c) 2020-2021, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __GST_DSEXAMPLE_H__ +#define __GST_DSEXAMPLE_H__ + +#include +#include + +/* Open CV headers */ +#ifdef WITH_OPENCV +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" +#endif + +#include +#include +#include "nvbufsurface.h" +#include "nvbufsurftransform.h" +#include "gst-nvquery.h" +#include "gstnvdsmeta.h" +#include "dsexample_lib/dsexample_lib.h" +#include "nvtx3/nvToolsExt.h" + +#include +#include +#include +#include + +/* Package and library details required for plugin_init */ +#define PACKAGE "dsexample" +#define VERSION "1.0" +#define LICENSE "Proprietary" +#define DESCRIPTION "NVIDIA example plugin for integration with DeepStream on DGPU/Jetson" +#define BINARY_PACKAGE "NVIDIA DeepStream 3rdparty IP integration example plugin" +#define URL "http://nvidia.com/" + + +G_BEGIN_DECLS +/* Standard boilerplate stuff */ +typedef struct _GstDsExample GstDsExample; +typedef struct _GstDsExampleClass GstDsExampleClass; + +/* Standard boilerplate stuff */ +#define GST_TYPE_DSEXAMPLE (gst_dsexample_get_type()) +#define GST_DSEXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DSEXAMPLE,GstDsExample)) +#define GST_DSEXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DSEXAMPLE,GstDsExampleClass)) +#define GST_DSEXAMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_DSEXAMPLE, GstDsExampleClass)) +#define GST_IS_DSEXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DSEXAMPLE)) +#define GST_IS_DSEXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DSEXAMPLE)) +#define GST_DSEXAMPLE_CAST(obj) ((GstDsExample *)(obj)) + +/** Maximum batch size to be supported by dsexample. */ +#define NVDSEXAMPLE_MAX_BATCH_SIZE G_MAXUINT + +struct _GstDsExample +{ + GstBaseTransform base_trans; + + /** Context of the custom algorithm library */ + DsExampleCtx *dsexamplelib_ctx; + + /** Processing Queue and related synchronization structures. */ + + /** Gmutex lock for against shared access in threads**/ + GMutex process_lock; + + /** Queue to send data to output thread for processing**/ + GQueue *process_queue; + + /** Gcondition for process queue**/ + GCond process_cond; + + /**Queue to receive processed data from output thread **/ + GQueue *buf_queue; + + /** Gcondition for buf queue **/ + GCond buf_cond; + + /** Output thread. */ + GThread *process_thread; + + /** Boolean to signal output thread to stop. */ + gboolean stop; + + /** Unique ID of the element. Used to identify metadata + * generated by this element. */ + guint unique_id; + + /** Frame number of the current input buffer */ + guint64 frame_num; + + /** CUDA Stream used for allocating the CUDA task */ + cudaStream_t cuda_stream; + + /** Temporary NvBufSurface for batched transformations. */ + NvBufSurface batch_insurf; + + /** the intermediate scratch buffer for conversions RGBA */ + NvBufSurface *inter_buf; + + /** Input video info (resolution, color format, framerate, etc) */ + GstVideoInfo video_info; + + /** Resolution at which frames/objects should be processed */ + gint processing_width; + gint processing_height; + + /** Maximum batch size. */ + guint max_batch_size; + + /** GPU ID on which we expect to execute the task */ + guint gpu_id; + + /** Boolean indicating if entire frame or cropped objects should be processed */ + gboolean process_full_frame; + + /** Current batch number of the input batch. */ + gulong current_batch_num; + + /** GstFlowReturn returned by the latest buffer pad push. */ + GstFlowReturn last_flow_ret; + + /** Config params required by NvBufSurfTransform API. */ + NvBufSurfTransformConfigParams transform_config_params; + + /** Parameters to use for transforming buffers. */ + NvBufSurfTransformParams transform_params; + + /** NVTX Domain. */ + nvtxDomainHandle_t nvtx_domain; +}; + +typedef struct +{ + /** Ratio by which the frame / object crop was scaled in the horizontal + * direction. Required when scaling co-ordinates/sizes in metadata + * back to input resolution. */ + gdouble scale_ratio_x = 0.0; + /** Ratio by which the frame / object crop was scaled in the vertical + * direction. Required when scaling co-ordinates/sizes in metadata + * back to input resolution. */ + gdouble scale_ratio_y = 0.0; + /** NvDsObjectParams belonging to the object to be classified. */ + NvDsObjectMeta *obj_meta = nullptr; + NvDsFrameMeta *frame_meta = nullptr; + /** Index of the frame in the batched input GstBuffer. Not required for + * classifiers. */ + guint batch_index = 0; + /** Frame number of the frame from the source. */ + gulong frame_num = 0; + /** The buffer structure the object / frame was converted from. */ + NvBufSurfaceParams *input_surf_params = nullptr; +} GstDsExampleFrame; + +/** + * Holds information about the batch of frames to be inferred. + */ +typedef struct +{ + /** Vector of frames in the batch. */ + std::vector < GstDsExampleFrame > frames; + /** Pointer to the input GstBuffer. */ + GstBuffer *inbuf = nullptr; + /** Batch number of the input batch. */ + gulong inbuf_batch_num = 0; + /** Boolean indicating that the output thread should only push the buffer to + * downstream element. If set to true, a corresponding batch has not been + * queued at the input of NvDsExampleContext and hence dequeuing of output is + * not required. */ + gboolean push_buffer = FALSE; + /** Boolean marking this batch as an event marker. This is only used for + * synchronization. The output loop does not process on the batch. + */ + gboolean event_marker = FALSE; + +#ifdef WITH_OPENCV + /** OpenCV mat containing RGB data */ + cv::Mat * cvmat; +#else + NvBufSurface *inter_buf; +#endif + + nvtxRangeId_t nvtx_complete_buf_range = 0; +} GstDsExampleBatch; + +/** Boiler plate stuff */ +struct _GstDsExampleClass +{ + GstBaseTransformClass parent_class; +}; + +GType gst_dsexample_get_type (void); + +G_END_DECLS +#endif /* __GST_DSEXAMPLE_H__ */ diff --git a/include/CharacterDetection.h b/include/CharacterDetection.h new file mode 100644 index 0000000..03e51f6 --- /dev/null +++ b/include/CharacterDetection.h @@ -0,0 +1,92 @@ +#pragma once + +#include "layer.h" +#include "net.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "algorithm" +#include "vector" +#include +#include +#include "config.h" + +class YoloV5FocusCharacterDetection : public ncnn::Layer +{ +public: + YoloV5FocusCharacterDetection() + { + one_blob_only = true; + } + + virtual int forward(const ncnn::Mat& bottom_blob, ncnn::Mat& top_blob, const ncnn::Option& opt) const + { + int w = bottom_blob.w; + int h = bottom_blob.h; + int channels = bottom_blob.c; + + int outw = w / 2; + int outh = h / 2; + int outc = channels * 4; + + top_blob.create(outw, outh, outc, 4u, 1, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + #pragma omp parallel for num_threads(opt.num_threads) + for (int p = 0; p < outc; p++) + { + const float* ptr = bottom_blob.channel(p % channels).row((p / channels) % 2) + ((p / channels) / 2); + float* outptr = top_blob.channel(p); + + for (int i = 0; i < outh; i++) + { + for (int j = 0; j < outw; j++) + { + *outptr = *ptr; + + outptr += 1; + ptr += 2; + } + + ptr += w; + } + } + + return 0; + } +}; + +class CharacterDetector{ +public: + CharacterDetector(); + inline float intersection_area(const Object& a, const Object& b); + void qsort_descent_inplace(std::vector& faceobjects, int left, int right); + void qsort_descent_inplace(std::vector& objects); + void nms_sorted_bboxes(const std::vector& faceobjects, std::vector& picked, float nms_threshold); + void generate_grids_and_stride(const int target_size, std::vector& strides, std::vector& grid_strides); + void generate_yolox_proposals(std::vector grid_strides, const ncnn::Mat& feat_blob, float prob_threshold, std::vector& objects); + + std::vector nms(std::vector &chars); + std::string cluster(std::vector &chars, std::string mode, bool& isModeCorrect); + bool isOverlaped(cv::Rect rect1, cv::Rect rect2); + std::vector splitOCR(std::string rawOcr); + std::vector splitString(const std::string& s, const std::string& c); + + std::vector Detect(cv::Mat frame); + std::string extract(cv::Mat rawPlate, std::string mode); +private: + float minWidth = 15; + int useRuleHead = 0; + int useRuleMid = 0; + int useRuleTail = 0; + ncnn::Net net; + float yolox_nms_thresh = 0.3; + float yolox_conf_thresh = 0.3; + int yolox_target_size = 416; +}; \ No newline at end of file diff --git a/include/CppThread.h b/include/CppThread.h new file mode 100755 index 0000000..3a8145f --- /dev/null +++ b/include/CppThread.h @@ -0,0 +1,70 @@ +#ifndef __CPP_THREAD_H_ +#define __CPP_THREAD_H_ + +/** + * GNU GENERAL PUBLIC LICENSE + * Version 3, 29 June 2007 + * + * (C) 2020-2021, Bernd Porr + **/ + +#include + +/** + * A thin wrapper around the C++ thread model to avoid + * a static callback. Instead just inherit this class + * and overload run() which then runs in this thread. + * This is header-only so that it can be performed + * inline for max performance. + **/ +class CppThread { + +public: + /** + * Starts the thread. + **/ + inline void start() { + isRun = true; + if (mthread) return; + mthread=new std::thread([this]{this->run();}); + } + + inline void sleep(int time) { + std::this_thread::sleep_for(std::chrono::milliseconds(time)); + } + + /** + * Waits for the thread to terminate. + **/ + inline void join() { + if (nullptr != mthread) { + mthread->join(); + mthread = nullptr; + } + } + + inline void stop() { + if (!mthread) return; + delete mthread; + } + + inline bool isRunning() { + return this->isRun; + } + +protected: + /** + * This method does all the work of this thread. + * Overload this abstract function with + * a real one doing the actual work of this thread. + **/ + virtual void run() = 0; + +private: + bool isRun = false; + // pointer to the thread + std::thread *mthread=NULL; +}; + + +#endif diff --git a/include/CropLP.h b/include/CropLP.h new file mode 100644 index 0000000..0263214 --- /dev/null +++ b/include/CropLP.h @@ -0,0 +1,59 @@ +#include +#include "structs.h" +#include +#include "cuda_runtime_api.h" +#include "CropLP_logging.h" +#include "CropLP_common.hpp" +#include +#define DEVICE 0 +#define NET s // s m l x +#define NETSTRUCT(str) createEngine_##str +#define CREATENET(net) NETSTRUCT(net) +#define STR1(x) #x +#define STR2(x) STR1(x) +// #define USE_FP16 // comment out this if want to use FP16 +#define CONF_THRESH 0.51 +#define BATCH_SIZE 1 +// stuff we know about the network and the input/output blobs + +static const int INPUT_H_UNET = 224; +static const int INPUT_W_UNET = 224; +static const int OUTPUT_SIZE_UNET = 224*224; + +using namespace nvinfer1; +static Logger gLogger; + +struct DetectionCropLP{ + float mask[INPUT_W_UNET * INPUT_H_UNET * 1]; +}; + +class CropLP{ + private: + std::string model_path = "/home/thai/py_script/MTA/unet-segment/unet/license_ckpt_crop/22-0.9823-0.0604.trt"; + char *trtModelStream{nullptr}; + size_t size{0}; + IRuntime* runtime{nullptr}; + ICudaEngine* engine{nullptr}; + IExecutionContext* context{nullptr}; + const char* INPUT_BLOB_NAME_UNET = "input_1"; + const char* OUTPUT_BLOB_NAME_UNET = "conv2d_23"; + + + public: + static CropLP &getInst() + { + static CropLP instance; + return instance; + }; + CropLP(); + void _init(); + float eculidDistance(cv::Point p1, cv::Point p2); + void validate_point(cv::Point2f &tl, cv::Point2f &tr, cv::Point2f &br, cv::Point2f &bl, cv::Mat img_ori); + cv::Mat preprocess_img(cv::Mat& img); + void doInference(IExecutionContext& context, float* input, float* output, int batchSize); + void process_cls_result(DetectionCropLP &res, float *output); + float sigmoid(float x); + cv::Mat segmentation(cv::Mat img); + cv::Mat Crop(cv::Mat mask, cv::Mat img_ori, std::string mode); + std::vector predict(cv::Mat inputImage, std::string mode); +}; \ No newline at end of file diff --git a/include/CropLP_common.hpp b/include/CropLP_common.hpp new file mode 100755 index 0000000..0551e57 --- /dev/null +++ b/include/CropLP_common.hpp @@ -0,0 +1,148 @@ +#ifndef UNET_COMMON_H_ +#define UNET_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include "NvInfer.h" + + +#define CHECK(status) \ + do\ + {\ + auto ret = (status);\ + if (ret != 0)\ + {\ + std::cerr << "Cuda failure: " << ret << std::endl;\ + abort();\ + }\ + } while (0) + +using namespace nvinfer1; + + + + + +// TensorRT weight files have a simple space delimited format: +// [type] [size] +// std::map loadWeights(const std::string file) { +// std::cout << "Loading weights: " << file << std::endl; +// std::map weightMap; + +// // Open weights file +// std::ifstream input(file); +// assert(input.is_open() && "Unable to load weight file. please check if the .wts file path is right!!!!!!"); + +// // Read number of weight blobs +// int32_t count; +// input >> count; +// assert(count > 0 && "Invalid weight map file."); + +// while (count--) +// { +// Weights wt{DataType::kFLOAT, nullptr, 0}; +// uint32_t size; + +// // Read name and type of blob +// std::string name; +// input >> name >> std::dec >> size; +// wt.type = DataType::kFLOAT; + +// // Load blob +// uint32_t* val = reinterpret_cast(malloc(sizeof(val) * size)); +// for (uint32_t x = 0, y = size; x < y; ++x) +// { +// input >> std::hex >> val[x]; +// } +// wt.values = val; + +// wt.count = size; +// weightMap[name] = wt; +// } + +// return weightMap; +// } + +// IScaleLayer* addBatchNorm2d(INetworkDefinition *network, std::map& weightMap, ITensor& input, std::string lname, float eps) { +// float *gamma = (float*)weightMap[lname + ".weight"].values; +// float *beta = (float*)weightMap[lname + ".bias"].values; +// float *mean = (float*)weightMap[lname + ".running_mean"].values; +// float *var = (float*)weightMap[lname + ".running_var"].values; +// int len = weightMap[lname + ".running_var"].count; + +// float *scval = reinterpret_cast(malloc(sizeof(float) * len)); +// for (int i = 0; i < len; i++) { +// scval[i] = gamma[i] / sqrt(var[i] + eps); +// } +// Weights scale{DataType::kFLOAT, scval, len}; + +// float *shval = reinterpret_cast(malloc(sizeof(float) * len)); +// for (int i = 0; i < len; i++) { +// shval[i] = beta[i] - mean[i] * gamma[i] / sqrt(var[i] + eps); +// } +// Weights shift{DataType::kFLOAT, shval, len}; + +// float *pval = reinterpret_cast(malloc(sizeof(float) * len)); +// for (int i = 0; i < len; i++) { +// pval[i] = 1.0; +// } +// Weights power{DataType::kFLOAT, pval, len}; + +// weightMap[lname + ".scale"] = scale; +// weightMap[lname + ".shift"] = shift; +// weightMap[lname + ".power"] = power; +// IScaleLayer* scale_1 = network->addScale(input, ScaleMode::kCHANNEL, shift, scale, power); +// assert(scale_1); +// return scale_1; +// } + + +// ILayer* convBlock(INetworkDefinition *network, std::map& weightMap, ITensor& input, int outch, int ksize, int s, int g, std::string lname) { +// Weights emptywts{DataType::kFLOAT, nullptr, 0}; +// int p = ksize / 2; +// IConvolutionLayer* conv1 = network->addConvolutionNd(input, outch, DimsHW{ksize, ksize}, weightMap[lname + ".conv.weight"], emptywts); +// assert(conv1); +// conv1->setStrideNd(DimsHW{s, s}); +// conv1->setPaddingNd(DimsHW{p, p}); +// conv1->setNbGroups(g); +// IScaleLayer* bn1 = addBatchNorm2d(network, weightMap, *conv1->getOutput(0), lname + ".bn", 1e-3); + +// // hard_swish = x * hard_sigmoid +// auto hsig = network->addActivation(*bn1->getOutput(0), ActivationType::kHARD_SIGMOID); +// assert(hsig); +// hsig->setAlpha(1.0 / 6.0); +// hsig->setBeta(0.5); +// auto ew = network->addElementWise(*bn1->getOutput(0), *hsig->getOutput(0), ElementWiseOperation::kPROD); +// assert(ew); +// return ew; +// } + + + +// int read_files_in_dir(const char *p_dir_name, std::vector &file_names) { +// DIR *p_dir = opendir(p_dir_name); +// if (p_dir == nullptr) { +// return -1; +// } + +// struct dirent* p_file = nullptr; +// while ((p_file = readdir(p_dir)) != nullptr) { +// if (strcmp(p_file->d_name, ".") != 0 && +// strcmp(p_file->d_name, "..") != 0) { +// //std::string cur_file_name(p_dir_name); +// //cur_file_name += "/"; +// //cur_file_name += p_file->d_name; +// std::string cur_file_name(p_file->d_name); +// file_names.push_back(cur_file_name); +// } +// } + +// closedir(p_dir); +// return 0; +// } + +#endif diff --git a/include/CropLP_logging.h b/include/CropLP_logging.h new file mode 100755 index 0000000..af5747c --- /dev/null +++ b/include/CropLP_logging.h @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * 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. + */ + +#ifndef TENSORRT_LOGGING_H +#define TENSORRT_LOGGING_H + +#include "NvInferRuntimeCommon.h" +#include +#include +#include +#include +#include +#include +#include + +using Severity = nvinfer1::ILogger::Severity; + +class LogStreamConsumerBuffer : public std::stringbuf +{ +public: + LogStreamConsumerBuffer(std::ostream& stream, const std::string& prefix, bool shouldLog) + : mOutput(stream) + , mPrefix(prefix) + , mShouldLog(shouldLog) + { + } + + LogStreamConsumerBuffer(LogStreamConsumerBuffer&& other) + : mOutput(other.mOutput) + { + } + + ~LogStreamConsumerBuffer() + { + // std::streambuf::pbase() gives a pointer to the beginning of the buffered part of the output sequence + // std::streambuf::pptr() gives a pointer to the current position of the output sequence + // if the pointer to the beginning is not equal to the pointer to the current position, + // call putOutput() to log the output to the stream + if (pbase() != pptr()) + { + putOutput(); + } + } + + // synchronizes the stream buffer and returns 0 on success + // synchronizing the stream buffer consists of inserting the buffer contents into the stream, + // resetting the buffer and flushing the stream + virtual int sync() + { + putOutput(); + return 0; + } + + void putOutput() + { + if (mShouldLog) + { + // prepend timestamp + std::time_t timestamp = std::time(nullptr); + tm* tm_local = std::localtime(×tamp); + std::cout << "["; + std::cout << std::setw(2) << std::setfill('0') << 1 + tm_local->tm_mon << "/"; + std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_mday << "/"; + std::cout << std::setw(4) << std::setfill('0') << 1900 + tm_local->tm_year << "-"; + std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_hour << ":"; + std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_min << ":"; + std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_sec << "] "; + // std::stringbuf::str() gets the string contents of the buffer + // insert the buffer contents pre-appended by the appropriate prefix into the stream + mOutput << mPrefix << str(); + // set the buffer to empty + str(""); + // flush the stream + mOutput.flush(); + } + } + + void setShouldLog(bool shouldLog) + { + mShouldLog = shouldLog; + } + +private: + std::ostream& mOutput; + std::string mPrefix; + bool mShouldLog; +}; + +//! +//! \class LogStreamConsumerBase +//! \brief Convenience object used to initialize LogStreamConsumerBuffer before std::ostream in LogStreamConsumer +//! +class LogStreamConsumerBase +{ +public: + LogStreamConsumerBase(std::ostream& stream, const std::string& prefix, bool shouldLog) + : mBuffer(stream, prefix, shouldLog) + { + } + +protected: + LogStreamConsumerBuffer mBuffer; +}; + +//! +//! \class LogStreamConsumer +//! \brief Convenience object used to facilitate use of C++ stream syntax when logging messages. +//! Order of base classes is LogStreamConsumerBase and then std::ostream. +//! This is because the LogStreamConsumerBase class is used to initialize the LogStreamConsumerBuffer member field +//! in LogStreamConsumer and then the address of the buffer is passed to std::ostream. +//! This is necessary to prevent the address of an uninitialized buffer from being passed to std::ostream. +//! Please do not change the order of the parent classes. +//! +class LogStreamConsumer : protected LogStreamConsumerBase, public std::ostream +{ +public: + //! \brief Creates a LogStreamConsumer which logs messages with level severity. + //! Reportable severity determines if the messages are severe enough to be logged. + LogStreamConsumer(Severity reportableSeverity, Severity severity) + : LogStreamConsumerBase(severityOstream(severity), severityPrefix(severity), severity <= reportableSeverity) + , std::ostream(&mBuffer) // links the stream buffer with the stream + , mShouldLog(severity <= reportableSeverity) + , mSeverity(severity) + { + } + + LogStreamConsumer(LogStreamConsumer&& other) + : LogStreamConsumerBase(severityOstream(other.mSeverity), severityPrefix(other.mSeverity), other.mShouldLog) + , std::ostream(&mBuffer) // links the stream buffer with the stream + , mShouldLog(other.mShouldLog) + , mSeverity(other.mSeverity) + { + } + + void setReportableSeverity(Severity reportableSeverity) + { + mShouldLog = mSeverity <= reportableSeverity; + mBuffer.setShouldLog(mShouldLog); + } + +private: + static std::ostream& severityOstream(Severity severity) + { + return severity >= Severity::kINFO ? std::cout : std::cerr; + } + + static std::string severityPrefix(Severity severity) + { + switch (severity) + { + case Severity::kINTERNAL_ERROR: return "[F] "; + case Severity::kERROR: return "[E] "; + case Severity::kWARNING: return "[W] "; + case Severity::kINFO: return "[I] "; + case Severity::kVERBOSE: return "[V] "; + default: assert(0); return ""; + } + } + + bool mShouldLog; + Severity mSeverity; +}; + +//! \class Logger +//! +//! \brief Class which manages logging of TensorRT tools and samples +//! +//! \details This class provides a common interface for TensorRT tools and samples to log information to the console, +//! and supports logging two types of messages: +//! +//! - Debugging messages with an associated severity (info, warning, error, or internal error/fatal) +//! - Test pass/fail messages +//! +//! The advantage of having all samples use this class for logging as opposed to emitting directly to stdout/stderr is +//! that the logic for controlling the verbosity and formatting of sample output is centralized in one location. +//! +//! In the future, this class could be extended to support dumping test results to a file in some standard format +//! (for example, JUnit XML), and providing additional metadata (e.g. timing the duration of a test run). +//! +//! TODO: For backwards compatibility with existing samples, this class inherits directly from the nvinfer1::ILogger +//! interface, which is problematic since there isn't a clean separation between messages coming from the TensorRT +//! library and messages coming from the sample. +//! +//! In the future (once all samples are updated to use Logger::getTRTLogger() to access the ILogger) we can refactor the +//! class to eliminate the inheritance and instead make the nvinfer1::ILogger implementation a member of the Logger +//! object. + +class Logger : public nvinfer1::ILogger +{ +public: + Logger(Severity severity = Severity::kWARNING) + : mReportableSeverity(severity) + { + } + + //! + //! \enum TestResult + //! \brief Represents the state of a given test + //! + enum class TestResult + { + kRUNNING, //!< The test is running + kPASSED, //!< The test passed + kFAILED, //!< The test failed + kWAIVED //!< The test was waived + }; + + //! + //! \brief Forward-compatible method for retrieving the nvinfer::ILogger associated with this Logger + //! \return The nvinfer1::ILogger associated with this Logger + //! + //! TODO Once all samples are updated to use this method to register the logger with TensorRT, + //! we can eliminate the inheritance of Logger from ILogger + //! + nvinfer1::ILogger& getTRTLogger() + { + return *this; + } + + //! + //! \brief Implementation of the nvinfer1::ILogger::log() virtual method + //! + //! Note samples should not be calling this function directly; it will eventually go away once we eliminate the + //! inheritance from nvinfer1::ILogger + //! + void log(Severity severity, const char* msg) noexcept override + { + LogStreamConsumer(mReportableSeverity, severity) << "[TRT] " << std::string(msg) << std::endl; + } + + //! + //! \brief Method for controlling the verbosity of logging output + //! + //! \param severity The logger will only emit messages that have severity of this level or higher. + //! + void setReportableSeverity(Severity severity) + { + mReportableSeverity = severity; + } + + //! + //! \brief Opaque handle that holds logging information for a particular test + //! + //! This object is an opaque handle to information used by the Logger to print test results. + //! The sample must call Logger::defineTest() in order to obtain a TestAtom that can be used + //! with Logger::reportTest{Start,End}(). + //! + class TestAtom + { + public: + TestAtom(TestAtom&&) = default; + + private: + friend class Logger; + + TestAtom(bool started, const std::string& name, const std::string& cmdline) + : mStarted(started) + , mName(name) + , mCmdline(cmdline) + { + } + + bool mStarted; + std::string mName; + std::string mCmdline; + }; + + //! + //! \brief Define a test for logging + //! + //! \param[in] name The name of the test. This should be a string starting with + //! "TensorRT" and containing dot-separated strings containing + //! the characters [A-Za-z0-9_]. + //! For example, "TensorRT.sample_googlenet" + //! \param[in] cmdline The command line used to reproduce the test + // + //! \return a TestAtom that can be used in Logger::reportTest{Start,End}(). + //! + static TestAtom defineTest(const std::string& name, const std::string& cmdline) + { + return TestAtom(false, name, cmdline); + } + + //! + //! \brief A convenience overloaded version of defineTest() that accepts an array of command-line arguments + //! as input + //! + //! \param[in] name The name of the test + //! \param[in] argc The number of command-line arguments + //! \param[in] argv The array of command-line arguments (given as C strings) + //! + //! \return a TestAtom that can be used in Logger::reportTest{Start,End}(). + static TestAtom defineTest(const std::string& name, int argc, char const* const* argv) + { + auto cmdline = genCmdlineString(argc, argv); + return defineTest(name, cmdline); + } + + //! + //! \brief Report that a test has started. + //! + //! \pre reportTestStart() has not been called yet for the given testAtom + //! + //! \param[in] testAtom The handle to the test that has started + //! + static void reportTestStart(TestAtom& testAtom) + { + reportTestResult(testAtom, TestResult::kRUNNING); + assert(!testAtom.mStarted); + testAtom.mStarted = true; + } + + //! + //! \brief Report that a test has ended. + //! + //! \pre reportTestStart() has been called for the given testAtom + //! + //! \param[in] testAtom The handle to the test that has ended + //! \param[in] result The result of the test. Should be one of TestResult::kPASSED, + //! TestResult::kFAILED, TestResult::kWAIVED + //! + static void reportTestEnd(const TestAtom& testAtom, TestResult result) + { + assert(result != TestResult::kRUNNING); + assert(testAtom.mStarted); + reportTestResult(testAtom, result); + } + + static int reportPass(const TestAtom& testAtom) + { + reportTestEnd(testAtom, TestResult::kPASSED); + return EXIT_SUCCESS; + } + + static int reportFail(const TestAtom& testAtom) + { + reportTestEnd(testAtom, TestResult::kFAILED); + return EXIT_FAILURE; + } + + static int reportWaive(const TestAtom& testAtom) + { + reportTestEnd(testAtom, TestResult::kWAIVED); + return EXIT_SUCCESS; + } + + static int reportTest(const TestAtom& testAtom, bool pass) + { + return pass ? reportPass(testAtom) : reportFail(testAtom); + } + + Severity getReportableSeverity() const + { + return mReportableSeverity; + } + +private: + //! + //! \brief returns an appropriate string for prefixing a log message with the given severity + //! + static const char* severityPrefix(Severity severity) + { + switch (severity) + { + case Severity::kINTERNAL_ERROR: return "[F] "; + case Severity::kERROR: return "[E] "; + case Severity::kWARNING: return "[W] "; + case Severity::kINFO: return "[I] "; + case Severity::kVERBOSE: return "[V] "; + default: assert(0); return ""; + } + } + + //! + //! \brief returns an appropriate string for prefixing a test result message with the given result + //! + static const char* testResultString(TestResult result) + { + switch (result) + { + case TestResult::kRUNNING: return "RUNNING"; + case TestResult::kPASSED: return "PASSED"; + case TestResult::kFAILED: return "FAILED"; + case TestResult::kWAIVED: return "WAIVED"; + default: assert(0); return ""; + } + } + + //! + //! \brief returns an appropriate output stream (cout or cerr) to use with the given severity + //! + static std::ostream& severityOstream(Severity severity) + { + return severity >= Severity::kINFO ? std::cout : std::cerr; + } + + //! + //! \brief method that implements logging test results + //! + static void reportTestResult(const TestAtom& testAtom, TestResult result) + { + severityOstream(Severity::kINFO) << "&&&& " << testResultString(result) << " " << testAtom.mName << " # " + << testAtom.mCmdline << std::endl; + } + + //! + //! \brief generate a command line string from the given (argc, argv) values + //! + static std::string genCmdlineString(int argc, char const* const* argv) + { + std::stringstream ss; + for (int i = 0; i < argc; i++) + { + if (i > 0) + ss << " "; + ss << argv[i]; + } + return ss.str(); + } + + Severity mReportableSeverity; +}; + +namespace +{ + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kVERBOSE +//! +//! Example usage: +//! +//! LOG_VERBOSE(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_VERBOSE(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kVERBOSE); +} + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kINFO +//! +//! Example usage: +//! +//! LOG_INFO(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_INFO(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINFO); +} + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kWARNING +//! +//! Example usage: +//! +//! LOG_WARN(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_WARN(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kWARNING); +} + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kERROR +//! +//! Example usage: +//! +//! LOG_ERROR(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_ERROR(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kERROR); +} + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kINTERNAL_ERROR +// ("fatal" severity) +//! +//! Example usage: +//! +//! LOG_FATAL(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_FATAL(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINTERNAL_ERROR); +} + +} // anonymous namespace + +#endif // TENSORRT_LOGGING_H \ No newline at end of file diff --git a/include/CropLicensePlate.h b/include/CropLicensePlate.h new file mode 100644 index 0000000..d681b70 --- /dev/null +++ b/include/CropLicensePlate.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include +#include "net.h" +#include +#include +#include "config.h" + +using namespace cv; +using namespace std; + +class CropPlate { + public: + CropPlate(); + vector cropFormFrame(cv::Mat frame, string mode); + + private: + ncnn::Net net; + int size_input; + float detect_threshold; + float img_size = 272.0; + float wh_ratio = 2.0; + + private: + void sort(std::vector &dLables); + cv::Mat cropImage4Point(cv::Point2f rect_points[], cv::Mat img, cv::Size size); + void memcpy_array(float dir[][4], float src[][4]); + float IOU(DLable label1, DLable label2); + std::vector nms(std::vector dLables, float iou_threshold=.5, float prob_threshold=.5); + float length(cv::Point2f p1, cv::Point2f p2); + vector reconstruct(cv::Mat img, ncnn::Mat out_probs, ncnn::Mat out_box, float threshold = 0.7, string mode = ""); +}; \ No newline at end of file diff --git a/include/GetPlateColor.h b/include/GetPlateColor.h new file mode 100644 index 0000000..3534b73 --- /dev/null +++ b/include/GetPlateColor.h @@ -0,0 +1,10 @@ + +#pragma once + +#include +#include "config.h" +#include +#include +#include + +std::string checkColorPlate(cv::Mat img_bgr, std::string mode); diff --git a/include/LPRprocessor.h b/include/LPRprocessor.h new file mode 100644 index 0000000..63ee0ae --- /dev/null +++ b/include/LPRprocessor.h @@ -0,0 +1,20 @@ +#pragma once +#include "iostream" +#include "CppThread.h" +#include "structs.h" +#include "LicensePlateRecognition.h" +#include "queue" +#include "mutex" + +class LPRprocessor : public CppThread +{ +public: + LPRprocessor(std::queue &qLicensePlate_, std::mutex &mutexThread_); + void run(); +private: + LicensePlateRecognizer licensePlateRecognizer; + std::queue &qLicensePlate; + std::mutex &mutexThread; + std::string dstSaveImg_0 = "/home/thai/Desktop/test-OCR/source_0/"; + std::string dstSaveImg_1 = "/home/thai/Desktop/test-OCR/source_1/"; +}; diff --git a/include/LicensePlateRecognition.h b/include/LicensePlateRecognition.h new file mode 100644 index 0000000..72564cb --- /dev/null +++ b/include/LicensePlateRecognition.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include +#include "GetPlateColor.h" +// #include "CropLicensePlate.h" +#include "CharacterDetection.h" +#include "CropLP.h" + +class LicensePlateRecognizer { + private: + // CropPlate cropPlate; + CropLP cropLP; + CharacterDetector characterDetector; + + public: + LicensePlateRecognizer(); + static LicensePlateRecognizer &getInst() + { + static LicensePlateRecognizer instance; + return instance; + }; + PlateDetail recognition(cv::Mat frame, std::string mode); +}; \ No newline at end of file diff --git a/include/YOLOv5/DetectorCOCO.h b/include/YOLOv5/DetectorCOCO.h new file mode 100644 index 0000000..16aa2a7 --- /dev/null +++ b/include/YOLOv5/DetectorCOCO.h @@ -0,0 +1,68 @@ + +#include +#include +#include +#include "cuda_utils.h" +#include "logging.h" +#include "utils.h" +#include "preprocess.h" +#include "structs.h" +#include +#include +#include +#include +#include +#include "NvInfer.h" +#include "yololayer.h" + +using namespace nvinfer1; + +#define USE_FP32 // set USE_INT8 or USE_FP16 or USE_FP32 +#define DEVICE 0 // GPU id +#define NMS_THRESH_YOLO 0.4 +#define CONF_THRESH_YOLO_HEAD 0.75 +#define CONF_THRESH_YOLO_CHAIR 0.8 +#define BATCH_SIZE_YOLO 1 +#define MAX_IMAGE_INPUT_SIZE_THRESH 3000 * 3000 // ensure it exceed the maximum size in the input images ! + +class DetectorCOCO{ + + public: + static DetectorCOCO &getInst() + { + static DetectorCOCO instance; + return instance; + }; + void _init(); + DetectorCOCO(); + cv::Rect get_rect_yolov5(cv::Mat& img, float bbox[4]); + float iou_yolov5(float lbox[4], float rbox[4]); + static bool cmp_yolov5(const Yolo::Detection& a, const Yolo::Detection& b); + void nms_yolov5(std::vector& res, float *output, float conf_thresh, float nms_thresh); + void doInference(IExecutionContext& context, cudaStream_t& stream, void **buffers, float* output, int batchSize); + std::vector predict(cv::Mat inputImage, std::string type); + + private: + const int INPUT_H = Yolo::INPUT_H; + const int INPUT_W = Yolo::INPUT_W; + const int CLASS_NUM = Yolo::CLASS_NUM; + const int OUTPUT_SIZE = Yolo::MAX_OUTPUT_BBOX_COUNT * sizeof(Yolo::Detection) / sizeof(float) + 1; + const char* INPUT_BLOB_NAME = "data"; + const char* OUTPUT_BLOB_NAME = "prob"; + Logger gLogger; + std::string engine_name_head = "/opt/nvidia/deepstream/deepstream-6.0/sources/apps/sample_apps/deepstream-app/Model_Classify/verify/crowdhuman_0-body_1-head__yolov5m.engine"; + std::string engine_name_chair = "/media/thai/A0B6A6B3B6A688FC2/code/PROJECT_BI/CLONE/tensorrtx/yolov5/build/20220615_weight_80class.engine"; + + IRuntime* runtime_head; + IRuntime* runtime_chair; + + ICudaEngine* engine_head; + ICudaEngine* engine_chair; + + IExecutionContext* context_head; + IExecutionContext* context_chair; + + + + +}; diff --git a/include/YOLOv5/cuda_utils.h b/include/YOLOv5/cuda_utils.h new file mode 100755 index 0000000..8fbd319 --- /dev/null +++ b/include/YOLOv5/cuda_utils.h @@ -0,0 +1,18 @@ +#ifndef TRTX_CUDA_UTILS_H_ +#define TRTX_CUDA_UTILS_H_ + +#include + +#ifndef CUDA_CHECK +#define CUDA_CHECK(callstr)\ + {\ + cudaError_t error_code = callstr;\ + if (error_code != cudaSuccess) {\ + std::cerr << "CUDA error " << error_code << " at " << __FILE__ << ":" << __LINE__;\ + assert(0);\ + }\ + } +#endif // CUDA_CHECK + +#endif // TRTX_CUDA_UTILS_H_ + diff --git a/include/YOLOv5/logging.h b/include/YOLOv5/logging.h new file mode 100755 index 0000000..6b79a8b --- /dev/null +++ b/include/YOLOv5/logging.h @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * 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. + */ + +#ifndef TENSORRT_LOGGING_H +#define TENSORRT_LOGGING_H + +#include "NvInferRuntimeCommon.h" +#include +#include +#include +#include +#include +#include +#include +#include "macros.h" + +using Severity = nvinfer1::ILogger::Severity; + +class LogStreamConsumerBuffer : public std::stringbuf +{ +public: + LogStreamConsumerBuffer(std::ostream& stream, const std::string& prefix, bool shouldLog) + : mOutput(stream) + , mPrefix(prefix) + , mShouldLog(shouldLog) + { + } + + LogStreamConsumerBuffer(LogStreamConsumerBuffer&& other) + : mOutput(other.mOutput) + { + } + + ~LogStreamConsumerBuffer() + { + // std::streambuf::pbase() gives a pointer to the beginning of the buffered part of the output sequence + // std::streambuf::pptr() gives a pointer to the current position of the output sequence + // if the pointer to the beginning is not equal to the pointer to the current position, + // call putOutput() to log the output to the stream + if (pbase() != pptr()) + { + putOutput(); + } + } + + // synchronizes the stream buffer and returns 0 on success + // synchronizing the stream buffer consists of inserting the buffer contents into the stream, + // resetting the buffer and flushing the stream + virtual int sync() + { + putOutput(); + return 0; + } + + void putOutput() + { + if (mShouldLog) + { + // prepend timestamp + std::time_t timestamp = std::time(nullptr); + tm* tm_local = std::localtime(×tamp); + std::cout << "["; + std::cout << std::setw(2) << std::setfill('0') << 1 + tm_local->tm_mon << "/"; + std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_mday << "/"; + std::cout << std::setw(4) << std::setfill('0') << 1900 + tm_local->tm_year << "-"; + std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_hour << ":"; + std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_min << ":"; + std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_sec << "] "; + // std::stringbuf::str() gets the string contents of the buffer + // insert the buffer contents pre-appended by the appropriate prefix into the stream + mOutput << mPrefix << str(); + // set the buffer to empty + str(""); + // flush the stream + mOutput.flush(); + } + } + + void setShouldLog(bool shouldLog) + { + mShouldLog = shouldLog; + } + +private: + std::ostream& mOutput; + std::string mPrefix; + bool mShouldLog; +}; + +//! +//! \class LogStreamConsumerBase +//! \brief Convenience object used to initialize LogStreamConsumerBuffer before std::ostream in LogStreamConsumer +//! +class LogStreamConsumerBase +{ +public: + LogStreamConsumerBase(std::ostream& stream, const std::string& prefix, bool shouldLog) + : mBuffer(stream, prefix, shouldLog) + { + } + +protected: + LogStreamConsumerBuffer mBuffer; +}; + +//! +//! \class LogStreamConsumer +//! \brief Convenience object used to facilitate use of C++ stream syntax when logging messages. +//! Order of base classes is LogStreamConsumerBase and then std::ostream. +//! This is because the LogStreamConsumerBase class is used to initialize the LogStreamConsumerBuffer member field +//! in LogStreamConsumer and then the address of the buffer is passed to std::ostream. +//! This is necessary to prevent the address of an uninitialized buffer from being passed to std::ostream. +//! Please do not change the order of the parent classes. +//! +class LogStreamConsumer : protected LogStreamConsumerBase, public std::ostream +{ +public: + //! \brief Creates a LogStreamConsumer which logs messages with level severity. + //! Reportable severity determines if the messages are severe enough to be logged. + LogStreamConsumer(Severity reportableSeverity, Severity severity) + : LogStreamConsumerBase(severityOstream(severity), severityPrefix(severity), severity <= reportableSeverity) + , std::ostream(&mBuffer) // links the stream buffer with the stream + , mShouldLog(severity <= reportableSeverity) + , mSeverity(severity) + { + } + + LogStreamConsumer(LogStreamConsumer&& other) + : LogStreamConsumerBase(severityOstream(other.mSeverity), severityPrefix(other.mSeverity), other.mShouldLog) + , std::ostream(&mBuffer) // links the stream buffer with the stream + , mShouldLog(other.mShouldLog) + , mSeverity(other.mSeverity) + { + } + + void setReportableSeverity(Severity reportableSeverity) + { + mShouldLog = mSeverity <= reportableSeverity; + mBuffer.setShouldLog(mShouldLog); + } + +private: + static std::ostream& severityOstream(Severity severity) + { + return severity >= Severity::kINFO ? std::cout : std::cerr; + } + + static std::string severityPrefix(Severity severity) + { + switch (severity) + { + case Severity::kINTERNAL_ERROR: return "[F] "; + case Severity::kERROR: return "[E] "; + case Severity::kWARNING: return "[W] "; + case Severity::kINFO: return "[I] "; + case Severity::kVERBOSE: return "[V] "; + default: assert(0); return ""; + } + } + + bool mShouldLog; + Severity mSeverity; +}; + +//! \class Logger +//! +//! \brief Class which manages logging of TensorRT tools and samples +//! +//! \details This class provides a common interface for TensorRT tools and samples to log information to the console, +//! and supports logging two types of messages: +//! +//! - Debugging messages with an associated severity (info, warning, error, or internal error/fatal) +//! - Test pass/fail messages +//! +//! The advantage of having all samples use this class for logging as opposed to emitting directly to stdout/stderr is +//! that the logic for controlling the verbosity and formatting of sample output is centralized in one location. +//! +//! In the future, this class could be extended to support dumping test results to a file in some standard format +//! (for example, JUnit XML), and providing additional metadata (e.g. timing the duration of a test run). +//! +//! TODO: For backwards compatibility with existing samples, this class inherits directly from the nvinfer1::ILogger +//! interface, which is problematic since there isn't a clean separation between messages coming from the TensorRT +//! library and messages coming from the sample. +//! +//! In the future (once all samples are updated to use Logger::getTRTLogger() to access the ILogger) we can refactor the +//! class to eliminate the inheritance and instead make the nvinfer1::ILogger implementation a member of the Logger +//! object. + +class Logger : public nvinfer1::ILogger +{ +public: + Logger(Severity severity = Severity::kWARNING) + : mReportableSeverity(severity) + { + } + + //! + //! \enum TestResult + //! \brief Represents the state of a given test + //! + enum class TestResult + { + kRUNNING, //!< The test is running + kPASSED, //!< The test passed + kFAILED, //!< The test failed + kWAIVED //!< The test was waived + }; + + //! + //! \brief Forward-compatible method for retrieving the nvinfer::ILogger associated with this Logger + //! \return The nvinfer1::ILogger associated with this Logger + //! + //! TODO Once all samples are updated to use this method to register the logger with TensorRT, + //! we can eliminate the inheritance of Logger from ILogger + //! + nvinfer1::ILogger& getTRTLogger() + { + return *this; + } + + //! + //! \brief Implementation of the nvinfer1::ILogger::log() virtual method + //! + //! Note samples should not be calling this function directly; it will eventually go away once we eliminate the + //! inheritance from nvinfer1::ILogger + //! + void log(Severity severity, const char* msg) TRT_NOEXCEPT override + { + LogStreamConsumer(mReportableSeverity, severity) << "[TRT] " << std::string(msg) << std::endl; + } + + //! + //! \brief Method for controlling the verbosity of logging output + //! + //! \param severity The logger will only emit messages that have severity of this level or higher. + //! + void setReportableSeverity(Severity severity) + { + mReportableSeverity = severity; + } + + //! + //! \brief Opaque handle that holds logging information for a particular test + //! + //! This object is an opaque handle to information used by the Logger to print test results. + //! The sample must call Logger::defineTest() in order to obtain a TestAtom that can be used + //! with Logger::reportTest{Start,End}(). + //! + class TestAtom + { + public: + TestAtom(TestAtom&&) = default; + + private: + friend class Logger; + + TestAtom(bool started, const std::string& name, const std::string& cmdline) + : mStarted(started) + , mName(name) + , mCmdline(cmdline) + { + } + + bool mStarted; + std::string mName; + std::string mCmdline; + }; + + //! + //! \brief Define a test for logging + //! + //! \param[in] name The name of the test. This should be a string starting with + //! "TensorRT" and containing dot-separated strings containing + //! the characters [A-Za-z0-9_]. + //! For example, "TensorRT.sample_googlenet" + //! \param[in] cmdline The command line used to reproduce the test + // + //! \return a TestAtom that can be used in Logger::reportTest{Start,End}(). + //! + static TestAtom defineTest(const std::string& name, const std::string& cmdline) + { + return TestAtom(false, name, cmdline); + } + + //! + //! \brief A convenience overloaded version of defineTest() that accepts an array of command-line arguments + //! as input + //! + //! \param[in] name The name of the test + //! \param[in] argc The number of command-line arguments + //! \param[in] argv The array of command-line arguments (given as C strings) + //! + //! \return a TestAtom that can be used in Logger::reportTest{Start,End}(). + static TestAtom defineTest(const std::string& name, int argc, char const* const* argv) + { + auto cmdline = genCmdlineString(argc, argv); + return defineTest(name, cmdline); + } + + //! + //! \brief Report that a test has started. + //! + //! \pre reportTestStart() has not been called yet for the given testAtom + //! + //! \param[in] testAtom The handle to the test that has started + //! + static void reportTestStart(TestAtom& testAtom) + { + reportTestResult(testAtom, TestResult::kRUNNING); + assert(!testAtom.mStarted); + testAtom.mStarted = true; + } + + //! + //! \brief Report that a test has ended. + //! + //! \pre reportTestStart() has been called for the given testAtom + //! + //! \param[in] testAtom The handle to the test that has ended + //! \param[in] result The result of the test. Should be one of TestResult::kPASSED, + //! TestResult::kFAILED, TestResult::kWAIVED + //! + static void reportTestEnd(const TestAtom& testAtom, TestResult result) + { + assert(result != TestResult::kRUNNING); + assert(testAtom.mStarted); + reportTestResult(testAtom, result); + } + + static int reportPass(const TestAtom& testAtom) + { + reportTestEnd(testAtom, TestResult::kPASSED); + return EXIT_SUCCESS; + } + + static int reportFail(const TestAtom& testAtom) + { + reportTestEnd(testAtom, TestResult::kFAILED); + return EXIT_FAILURE; + } + + static int reportWaive(const TestAtom& testAtom) + { + reportTestEnd(testAtom, TestResult::kWAIVED); + return EXIT_SUCCESS; + } + + static int reportTest(const TestAtom& testAtom, bool pass) + { + return pass ? reportPass(testAtom) : reportFail(testAtom); + } + + Severity getReportableSeverity() const + { + return mReportableSeverity; + } + +private: + //! + //! \brief returns an appropriate string for prefixing a log message with the given severity + //! + static const char* severityPrefix(Severity severity) + { + switch (severity) + { + case Severity::kINTERNAL_ERROR: return "[F] "; + case Severity::kERROR: return "[E] "; + case Severity::kWARNING: return "[W] "; + case Severity::kINFO: return "[I] "; + case Severity::kVERBOSE: return "[V] "; + default: assert(0); return ""; + } + } + + //! + //! \brief returns an appropriate string for prefixing a test result message with the given result + //! + static const char* testResultString(TestResult result) + { + switch (result) + { + case TestResult::kRUNNING: return "RUNNING"; + case TestResult::kPASSED: return "PASSED"; + case TestResult::kFAILED: return "FAILED"; + case TestResult::kWAIVED: return "WAIVED"; + default: assert(0); return ""; + } + } + + //! + //! \brief returns an appropriate output stream (cout or cerr) to use with the given severity + //! + static std::ostream& severityOstream(Severity severity) + { + return severity >= Severity::kINFO ? std::cout : std::cerr; + } + + //! + //! \brief method that implements logging test results + //! + static void reportTestResult(const TestAtom& testAtom, TestResult result) + { + severityOstream(Severity::kINFO) << "&&&& " << testResultString(result) << " " << testAtom.mName << " # " + << testAtom.mCmdline << std::endl; + } + + //! + //! \brief generate a command line string from the given (argc, argv) values + //! + static std::string genCmdlineString(int argc, char const* const* argv) + { + std::stringstream ss; + for (int i = 0; i < argc; i++) + { + if (i > 0) + ss << " "; + ss << argv[i]; + } + return ss.str(); + } + + Severity mReportableSeverity; +}; + +namespace +{ + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kVERBOSE +//! +//! Example usage: +//! +//! LOG_VERBOSE(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_VERBOSE(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kVERBOSE); +} + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kINFO +//! +//! Example usage: +//! +//! LOG_INFO(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_INFO(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINFO); +} + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kWARNING +//! +//! Example usage: +//! +//! LOG_WARN(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_WARN(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kWARNING); +} + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kERROR +//! +//! Example usage: +//! +//! LOG_ERROR(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_ERROR(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kERROR); +} + +//! +//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kINTERNAL_ERROR +// ("fatal" severity) +//! +//! Example usage: +//! +//! LOG_FATAL(logger) << "hello world" << std::endl; +//! +inline LogStreamConsumer LOG_FATAL(const Logger& logger) +{ + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINTERNAL_ERROR); +} + +} // anonymous namespace + +#endif // TENSORRT_LOGGING_H diff --git a/include/YOLOv5/macros.h b/include/YOLOv5/macros.h new file mode 100755 index 0000000..0e5b71b --- /dev/null +++ b/include/YOLOv5/macros.h @@ -0,0 +1,27 @@ +#ifndef __MACROS_H +#define __MACROS_H + +#ifdef API_EXPORTS +#if defined(_MSC_VER) +#define API __declspec(dllexport) +#else +#define API __attribute__((visibility("default"))) +#endif +#else + +#if defined(_MSC_VER) +#define API __declspec(dllimport) +#else +#define API +#endif +#endif // API_EXPORTS + +#if NV_TENSORRT_MAJOR >= 8 +#define TRT_NOEXCEPT noexcept +#define TRT_CONST_ENQUEUE const +#else +#define TRT_NOEXCEPT +#define TRT_CONST_ENQUEUE +#endif + +#endif // __MACROS_H diff --git a/include/YOLOv5/preprocess.h b/include/YOLOv5/preprocess.h new file mode 100755 index 0000000..236d5f3 --- /dev/null +++ b/include/YOLOv5/preprocess.h @@ -0,0 +1,16 @@ +#ifndef __PREPROCESS_H +#define __PREPROCESS_H + +#include +#include + + +struct AffineMatrix{ + float value[6]; +}; + + +void preprocess_kernel_img(uint8_t* src, int src_width, int src_height, + float* dst, int dst_width, int dst_height, + cudaStream_t stream); +#endif // __PREPROCESS_H diff --git a/include/YOLOv5/utils.h b/include/YOLOv5/utils.h new file mode 100755 index 0000000..fe50d03 --- /dev/null +++ b/include/YOLOv5/utils.h @@ -0,0 +1,52 @@ +#ifndef TRTX_YOLOV5_UTILS_H_ +#define TRTX_YOLOV5_UTILS_H_ + +#include +#include + +static inline cv::Mat preprocess_img(cv::Mat& img, int input_w, int input_h) { + int w, h, x, y; + float r_w = input_w / (img.cols*1.0); + float r_h = input_h / (img.rows*1.0); + if (r_h > r_w) { + w = input_w; + h = r_w * img.rows; + x = 0; + y = (input_h - h) / 2; + } else { + w = r_h * img.cols; + h = input_h; + x = (input_w - w) / 2; + y = 0; + } + cv::Mat re(h, w, CV_8UC3); + cv::resize(img, re, re.size(), 0, 0, cv::INTER_LINEAR); + cv::Mat out(input_h, input_w, CV_8UC3, cv::Scalar(128, 128, 128)); + re.copyTo(out(cv::Rect(x, y, re.cols, re.rows))); + return out; +} + +static inline int read_files_in_dir(const char *p_dir_name, std::vector &file_names) { + DIR *p_dir = opendir(p_dir_name); + if (p_dir == nullptr) { + return -1; + } + + struct dirent* p_file = nullptr; + while ((p_file = readdir(p_dir)) != nullptr) { + if (strcmp(p_file->d_name, ".") != 0 && + strcmp(p_file->d_name, "..") != 0) { + //std::string cur_file_name(p_dir_name); + //cur_file_name += "/"; + //cur_file_name += p_file->d_name; + std::string cur_file_name(p_file->d_name); + file_names.push_back(cur_file_name); + } + } + + closedir(p_dir); + return 0; +} + +#endif // TRTX_YOLOV5_UTILS_H_ + diff --git a/include/YOLOv5/yololayer.h b/include/YOLOv5/yololayer.h new file mode 100755 index 0000000..69c0eee --- /dev/null +++ b/include/YOLOv5/yololayer.h @@ -0,0 +1,138 @@ +#ifndef _YOLO_LAYER_H +#define _YOLO_LAYER_H + +#include +#include +#include +#include "macros.h" + +namespace Yolo +{ + static constexpr int CHECK_COUNT = 3; + static constexpr float IGNORE_THRESH = 0.1f; + struct YoloKernel + { + int width; + int height; + float anchors[CHECK_COUNT * 2]; + }; + static constexpr int MAX_OUTPUT_BBOX_COUNT = 1000; + static constexpr int CLASS_NUM = 80; + static constexpr int INPUT_H = 640; // yolov5's input height and width must be divisible by 32. + static constexpr int INPUT_W = 640; + + static constexpr int LOCATIONS = 4; + struct alignas(float) Detection { + //center_x center_y w h + float bbox[LOCATIONS]; + float conf; // bbox_conf * cls_conf + float class_id; + }; +} + +namespace nvinfer1 +{ + class API YoloLayerPlugin : public IPluginV2IOExt + { + public: + YoloLayerPlugin(int classCount, int netWidth, int netHeight, int maxOut, const std::vector& vYoloKernel); + YoloLayerPlugin(const void* data, size_t length); + ~YoloLayerPlugin(); + + int getNbOutputs() const TRT_NOEXCEPT override + { + return 1; + } + + Dims getOutputDimensions(int index, const Dims* inputs, int nbInputDims) TRT_NOEXCEPT override; + + int initialize() TRT_NOEXCEPT override; + + virtual void terminate() TRT_NOEXCEPT override {}; + + virtual size_t getWorkspaceSize(int maxBatchSize) const TRT_NOEXCEPT override { return 0; } + + virtual int enqueue(int batchSize, const void* const* inputs, void*TRT_CONST_ENQUEUE* outputs, void* workspace, cudaStream_t stream) TRT_NOEXCEPT override; + + virtual size_t getSerializationSize() const TRT_NOEXCEPT override; + + virtual void serialize(void* buffer) const TRT_NOEXCEPT override; + + bool supportsFormatCombination(int pos, const PluginTensorDesc* inOut, int nbInputs, int nbOutputs) const TRT_NOEXCEPT override { + return inOut[pos].format == TensorFormat::kLINEAR && inOut[pos].type == DataType::kFLOAT; + } + + const char* getPluginType() const TRT_NOEXCEPT override; + + const char* getPluginVersion() const TRT_NOEXCEPT override; + + void destroy() TRT_NOEXCEPT override; + + IPluginV2IOExt* clone() const TRT_NOEXCEPT override; + + void setPluginNamespace(const char* pluginNamespace) TRT_NOEXCEPT override; + + const char* getPluginNamespace() const TRT_NOEXCEPT override; + + DataType getOutputDataType(int index, const nvinfer1::DataType* inputTypes, int nbInputs) const TRT_NOEXCEPT override; + + bool isOutputBroadcastAcrossBatch(int outputIndex, const bool* inputIsBroadcasted, int nbInputs) const TRT_NOEXCEPT override; + + bool canBroadcastInputAcrossBatch(int inputIndex) const TRT_NOEXCEPT override; + + void attachToContext( + cudnnContext* cudnnContext, cublasContext* cublasContext, IGpuAllocator* gpuAllocator) TRT_NOEXCEPT override; + + void configurePlugin(const PluginTensorDesc* in, int nbInput, const PluginTensorDesc* out, int nbOutput) TRT_NOEXCEPT override; + + void detachFromContext() TRT_NOEXCEPT override; + + private: + void forwardGpu(const float* const* inputs, float *output, cudaStream_t stream, int batchSize = 1); + int mThreadCount = 256; + const char* mPluginNamespace; + int mKernelCount; + int mClassCount; + int mYoloV5NetWidth; + int mYoloV5NetHeight; + int mMaxOutObject; + std::vector mYoloKernel; + void** mAnchor; + }; + + class API YoloPluginCreator : public IPluginCreator + { + public: + YoloPluginCreator(); + + ~YoloPluginCreator() override = default; + + const char* getPluginName() const TRT_NOEXCEPT override; + + const char* getPluginVersion() const TRT_NOEXCEPT override; + + const PluginFieldCollection* getFieldNames() TRT_NOEXCEPT override; + + IPluginV2IOExt* createPlugin(const char* name, const PluginFieldCollection* fc) TRT_NOEXCEPT override; + + IPluginV2IOExt* deserializePlugin(const char* name, const void* serialData, size_t serialLength) TRT_NOEXCEPT override; + + void setPluginNamespace(const char* libNamespace) TRT_NOEXCEPT override + { + mNamespace = libNamespace; + } + + const char* getPluginNamespace() const TRT_NOEXCEPT override + { + return mNamespace.c_str(); + } + + private: + std::string mNamespace; + static PluginFieldCollection mFC; + static std::vector mPluginAttributes; + }; + REGISTER_TENSORRT_PLUGIN(YoloPluginCreator); +}; + +#endif // _YOLO_LAYER_H diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..69e4f17 --- /dev/null +++ b/include/config.h @@ -0,0 +1,23 @@ +#pragma once + +#include "json.hpp" +#include +#include +#include "structs.h" + +class CF +{ + public: + static CF& inst() { + static CF instance; + return instance; + } + CF(CF const&) = delete; + void operator=(CF const&) = delete; + void init(); + nlohmann::json data; + + private: + CF(); + std::string linkFileConfig = "/opt/nvidia/deepstream/deepstream-6.0/sources/gst-plugins/gst-dsexample-OCR/data/config.json"; +}; \ No newline at end of file diff --git a/include/json.hpp b/include/json.hpp new file mode 100755 index 0000000..0351074 --- /dev/null +++ b/include/json.hpp @@ -0,0 +1,24659 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.7.3 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 7 +#define NLOHMANN_JSON_VERSION_PATCH 3 + +#include // all_of, find, for_each +#include // assert +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +// Header is removed in C++20. +// See for more information. + +#if __cplusplus <= 201703L + #include // and, not, or +#endif + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // pair +// #include +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 13) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 13 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP \ +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + JSON_HEDLEY_RETURNS_NON_NULL + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template