diff --git a/CMakeLists.txt b/CMakeLists.txt index cba3f24..1152bb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.19) -project(BodyPipeline LANGUAGES CXX) +project(BodyPipeline LANGUAGES CXX CUDA) # Set C++ standard and enable modern practices set(CMAKE_CXX_STANDARD 17) @@ -27,7 +27,7 @@ endif() find_package(PkgConfig REQUIRED) -find_package(CUDA REQUIRED) +# find_package(CUDA REQUIRED) find_package(prometheus-cpp REQUIRED) pkg_check_modules(GLIB REQUIRED glib-2.0 gobject-2.0 nlohmann_json gstreamer-base-1.0 gstreamer-rtsp-server-1.0 gstreamer-rtsp-1.0 gstreamer-1.0 gstreamer-video-1.0) @@ -94,6 +94,18 @@ if(WIN32) target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS) endif() + +# Optionally set CUDA-specific flags +set_target_properties(${PROJECT_NAME} PROPERTIES + CUDA_STANDARD 17 # or 14, 20 depending on your code. Specifies which C++ standard to use for both host and device code. + CUDA_STANDARD_REQUIRED ON # Enforces the standard. Enforces that standard—avoids falling back to older versions silently. + CUDA_SEPARABLE_COMPILATION ON # Needed if kernels are in .cu files. Required if your project has multiple .cu files calling each other. + # CUDA_ARCHITECTURES 86 # Set to your GPU's arch (e.g., 86 for Ampere)Helps CMake compile only for the correct GPU architecture (you can use CMake's CUDA_ARCHITECTURES values). +) +# https://cmake.org/cmake/help/latest/prop_tgt/CUDA_ARCHITECTURES.html +# https://cmake.org/cmake/help/latest/policy/CMP0146.html + + # Include current directory for headers target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(${PROJECT_NAME} PRIVATE ${GLIB_INCLUDE_DIRS}) diff --git a/src/nv_infer_server_manager.cpp b/src/nv_infer_server_manager.cpp index fc8c782..58c2f2c 100644 --- a/src/nv_infer_server_manager.cpp +++ b/src/nv_infer_server_manager.cpp @@ -1,7 +1,7 @@ #include "nv_infer_server_manager.hpp" NvInferServerManager::NvInferServerManager() { - const auto& config = ConfigManager::get_instance().get_config(); + const auto &config = ConfigManager::get_instance().get_config(); pgie_batch_size = config["pgie_batch_size"]; inferserver_pgie_config_file = config["inferserver_pgie_config_file"].get(); @@ -26,5 +26,66 @@ bool NvInferServerManager::create_nv_infer_server(int num_sources) { g_object_set(G_OBJECT(primary_detector), "batch-size", num_sources, NULL); } + // std::cout << "✅ Found element: " << GST_ELEMENT_NAME(primary_detector) + // << std::endl; return true; +} + +// Probe function to inspect NvDsObjectMeta + +GstPadProbeReturn NvInferServerManager::osd_sink_pad_buffer_probe( + GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { + (void)pad; + (void)user_data; + GstBuffer *buf = (GstBuffer *)info->data; + + // Retrieve batch metadata from buffer + NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf); + if (!batch_meta) { + std::cerr << "No batch metadata found\n"; + exit(-1); + return GST_PAD_PROBE_OK; + } + + // probe sees the frame metadata (NvDsFrameMeta) — + // but no object metadata (NvDsObjectMeta) was attached to that frame. + + for (NvDsMetaList *l_frame = batch_meta->frame_meta_list; l_frame != NULL; + l_frame = l_frame->next) { + NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)(l_frame->data); + // std::cout << "Frame number: " << frame_meta->frame_num << std::endl; + // if (frame_meta->obj_meta_list == NULL) { + // std::cout << " ⚠️ No object metadata for this frame.\n"; + // } + + for (NvDsMetaList *l_obj = frame_meta->obj_meta_list; l_obj != NULL; + l_obj = l_obj->next) { + NvDsObjectMeta *obj_meta = (NvDsObjectMeta *)(l_obj->data); + + std::cout << " Object ID: " << obj_meta->object_id << std::endl; + std::cout << " Class ID: " << obj_meta->class_id << std::endl; + std::cout << " Label: " + << (obj_meta->obj_label ? obj_meta->obj_label : "N/A") + << std::endl; + std::cout << " BBox: x=" << obj_meta->rect_params.left + << " y=" << obj_meta->rect_params.top + << " w=" << obj_meta->rect_params.width + << " h=" << obj_meta->rect_params.height << std::endl; + } + } + + return GST_PAD_PROBE_OK; +} + +// Attach probe to a pad in the pipeline +void NvInferServerManager::attach_probe_to_element() { + GstPad *sink_pad = gst_element_get_static_pad(primary_detector, "sink"); + if (!sink_pad) { + std::cerr << "Unable to get sink pad\n"; + return; + } + + gst_pad_add_probe(sink_pad, GST_PAD_PROBE_TYPE_BUFFER, + osd_sink_pad_buffer_probe, NULL, NULL); + gst_object_unref(sink_pad); } \ No newline at end of file diff --git a/src/nv_infer_server_manager.hpp b/src/nv_infer_server_manager.hpp index f3ee463..ee3bc71 100644 --- a/src/nv_infer_server_manager.hpp +++ b/src/nv_infer_server_manager.hpp @@ -4,6 +4,7 @@ #include #include "config_manager.hpp" +#include "gstnvdsmeta.h" class NvInferServerManager { private: @@ -14,4 +15,8 @@ class NvInferServerManager { NvInferServerManager(); bool create_nv_infer_server(int); ~NvInferServerManager(); + static GstPadProbeReturn osd_sink_pad_buffer_probe(GstPad *, + GstPadProbeInfo *, + gpointer); + void attach_probe_to_element(); }; \ No newline at end of file diff --git a/src/pipeline_manager.cpp b/src/pipeline_manager.cpp index 5cd321b..4c981db 100644 --- a/src/pipeline_manager.cpp +++ b/src/pipeline_manager.cpp @@ -350,6 +350,13 @@ bool PipelineManager::create_pipeline_elements(int num_sources, rtsp_streaming_manager->updsink_port_num); nv_infer_server_manager->create_nv_infer_server(num_sources); + // GstElement *nvinfer = gst_bin_get_by_name(GST_BIN(pipeline), + // "primary-nvinference-engine"); + nv_infer_server_manager + ->attach_probe_to_element(); // nvinfer Or use "nvtracker" if after + // tracker + // gst_object_unref(nvinfer); + message_handling->create_message_handler(pipeline, g_run_forever, loop); setup_pipeline();