diff --git a/src/deepstream/pipelines/gpu_frames_skipping_pipeline.py b/src/deepstream/pipelines/gpu_frames_skipping_pipeline.py index d6ca165..19c731f 100644 --- a/src/deepstream/pipelines/gpu_frames_skipping_pipeline.py +++ b/src/deepstream/pipelines/gpu_frames_skipping_pipeline.py @@ -3,7 +3,7 @@ import cv2 import pyds import ctypes -from src.deepstream.probes.frame_comparison.gpu import frame_skipping_probe +from src.deepstream.probes.frame_comparison.gpu.frame_skipping_probe import frame_skipping_probe, GPUFrameChangeDetector from typing import Any, Dict, Optional @@ -20,10 +20,10 @@ stats: Dict[str, int] = {"total": 0, "skipped": 0, "processed": 0} -def jetson_frame_skip_probe(pad: Gst.Pad, info: Gst.PadProbeInfo, u_data: Optional[Any]) -> Gst.PadProbeReturn: +def gpu_frame_skip_probe(pad: Gst.Pad, info: Gst.PadProbeInfo, detector: GPUFrameChangeDetector) -> Gst.PadProbeReturn: buffer_ptr: int = hash(info.get_buffer()) batch_id: int = 0 - should_process: bool = frame_skipping_probe.frame_skipping_probe(buffer_ptr, batch_id) + should_process: bool = frame_skipping_probe(buffer_ptr, batch_id, detector) if should_process: stats["processed"] += 1 print(f"āœ… PROCESSING frame {stats['total']}") @@ -34,8 +34,8 @@ def jetson_frame_skip_probe(pad: Gst.Pad, info: Gst.PadProbeInfo, u_data: Option return Gst.PadProbeReturn.DROP def build_pipeline() -> Gst.Pipeline: - """Build Jetson-compatible pipeline""" - pipeline: Gst.Pipeline = Gst.Pipeline.new("jetson-frame-skipping-pipeline") + """Build GPU-compatible pipeline""" + pipeline: Gst.Pipeline = Gst.Pipeline.new("gpu-frame-skipping-pipeline") # Elements rtspsrc: Gst.Element = Gst.ElementFactory.make("rtspsrc", "source") @@ -62,7 +62,7 @@ def build_pipeline() -> Gst.Pipeline: streammux.set_property("width", 640) streammux.set_property("height", 480) nvinfer.set_property("config-file-path", CONFIG_FILE) - sink.set_property("location", os.path.join(OUTPUT_DIR, "jetson_frame_%05d.jpg")) + sink.set_property("location", os.path.join(OUTPUT_DIR, "frame_%05d.jpg")) caps: Gst.Caps = Gst.Caps.from_string("video/x-raw(memory:NVMM), format=RGBA") capsfilter.set_property("caps", caps) @@ -97,8 +97,10 @@ def on_pad_added_decode(src: Gst.Element, pad: Gst.Pad) -> None: srcpad.link(sinkpad) # Add probe + detector = GPUFrameChangeDetector() + streammux_src_pad: Gst.Pad = streammux.get_static_pad("src") - streammux_src_pad.add_probe(Gst.PadProbeType.BUFFER, jetson_frame_skip_probe, None) + streammux_src_pad.add_probe(Gst.PadProbeType.BUFFER, gpu_frame_skip_probe, detector) return pipeline @@ -109,7 +111,7 @@ def on_pad_added_decode(src: Gst.Element, pad: Gst.Pad) -> None: if stats["total"] > 0: skip_ratio: float = stats["skipped"] / stats["total"] - print(f"\nšŸ”„ Jetson Final Stats:") + print(f"\nšŸ”„ Final Stats:") print(f" Total: {stats['total']}") print(f" Processed: {stats['processed']}") print(f" Skipped: {stats['skipped']}") diff --git a/src/deepstream/probes/frame_comparison/gpu/frame_change_detector.cpp b/src/deepstream/probes/frame_comparison/gpu/frame_change_detector.cpp index 3d38bb4..7d679b6 100644 --- a/src/deepstream/probes/frame_comparison/gpu/frame_change_detector.cpp +++ b/src/deepstream/probes/frame_comparison/gpu/frame_change_detector.cpp @@ -5,18 +5,10 @@ #include #include -std::unique_ptr GPUFrameChangeDetector::instance = nullptr; GPUFrameChangeDetector::GPUFrameChangeDetector() : mse_thresh(500.0), ssim_thresh(0.99), flow_thresh(2.0), initialized(true) {} -GPUFrameChangeDetector* GPUFrameChangeDetector::getInstance() { - if (!instance) { - instance = std::unique_ptr(new GPUFrameChangeDetector()); - } - return instance.get(); -} - static cv::Scalar mean_gpu(const cv::cuda::GpuMat& mat) { cv::Scalar sum_val = cv::cuda::sum(mat); double total_elements = static_cast(mat.rows * mat.cols); @@ -118,7 +110,10 @@ GPUFrameChangeDetector::should_process_gpu_direct(const cv::cuda::GpuMat& gpu_fr bool is_static = (mse_val < 10.0 && ssim_val > 0.995 && flow_val < 0.05); - prev_frame_gpu = processed_curr; + bool should_proc = !is_static; + if (should_proc) { + prev_frame_gpu = processed_curr; + } - return {!is_static, {{"MSE", mse_val}, {"SSIM", ssim_val}, {"FLOW", flow_val}}}; + return {should_proc, {{"MSE", mse_val}, {"SSIM", ssim_val}, {"FLOW", flow_val}}}; } diff --git a/src/deepstream/probes/frame_comparison/gpu/frame_change_detector.hpp b/src/deepstream/probes/frame_comparison/gpu/frame_change_detector.hpp index 0def34a..66fda6e 100644 --- a/src/deepstream/probes/frame_comparison/gpu/frame_change_detector.hpp +++ b/src/deepstream/probes/frame_comparison/gpu/frame_change_detector.hpp @@ -6,17 +6,15 @@ class GPUFrameChangeDetector { public: - // Singleton access - static GPUFrameChangeDetector* getInstance(); - + // Main logic: decide if frame should be processed std::pair> should_process_gpu_direct(const cv::cuda::GpuMat& gpu_frame); -private: - // Constructor (private for singleton) GPUFrameChangeDetector(); +private: + // Internal processing functions cv::cuda::GpuMat preprocess_gpu(const cv::cuda::GpuMat& frame); double mse_gpu(const cv::cuda::GpuMat& imgA, const cv::cuda::GpuMat& imgB); @@ -24,7 +22,6 @@ class GPUFrameChangeDetector { double optical_flow_gpu(const cv::cuda::GpuMat& imgA, const cv::cuda::GpuMat& imgB); // Internal state - static std::unique_ptr instance; cv::cuda::GpuMat prev_frame_gpu; // Thresholds diff --git a/src/deepstream/probes/frame_comparison/gpu/frame_skipping_probe.cpp b/src/deepstream/probes/frame_comparison/gpu/frame_skipping_probe.cpp index 64ba1ba..3470104 100644 --- a/src/deepstream/probes/frame_comparison/gpu/frame_skipping_probe.cpp +++ b/src/deepstream/probes/frame_comparison/gpu/frame_skipping_probe.cpp @@ -10,7 +10,7 @@ namespace py = pybind11; -bool frame_skipping_probe(uintptr_t buffer_ptr, int batch_id) +bool frame_skipping_probe(uintptr_t buffer_ptr, int batch_id, GPUFrameChangeDetector& detector) { static int frame_count = 0; frame_count++; @@ -65,8 +65,7 @@ bool frame_skipping_probe(uintptr_t buffer_ptr, int batch_id) cv::cuda::GpuMat safe_copy; gpuMat.copyTo(safe_copy); - GPUFrameChangeDetector *detector = GPUFrameChangeDetector::getInstance(); - auto [should_process, metrics] = detector->should_process_gpu_direct(safe_copy); + auto [should_process, metrics] = detector.should_process_gpu_direct(safe_copy); safe_copy.release(); gpuMat.release(); @@ -98,6 +97,11 @@ bool frame_skipping_probe(uintptr_t buffer_ptr, int batch_id) PYBIND11_MODULE(frame_skipping_probe, m) { m.def("frame_skipping_probe", &frame_skipping_probe, - "Run DeepStream frame probe on GPU", - py::arg("buffer_ptr"), py::arg("batch_id")); + "Run DeepStream frame probe on GPU", + py::arg("buffer_ptr"), py::arg("batch_id"), py::arg("detector")); + + py::class_(m, "GPUFrameChangeDetector") + .def(py::init<>()) + .def("should_process_gpu_direct", &GPUFrameChangeDetector::should_process_gpu_direct); } + diff --git a/src/deepstream/probes/frame_comparison/gpu/frame_skipping_probe.cpython-310-aarch64-linux-gnu.so b/src/deepstream/probes/frame_comparison/gpu/frame_skipping_probe.cpython-310-aarch64-linux-gnu.so index 692fd04..136cf15 100755 Binary files a/src/deepstream/probes/frame_comparison/gpu/frame_skipping_probe.cpython-310-aarch64-linux-gnu.so and b/src/deepstream/probes/frame_comparison/gpu/frame_skipping_probe.cpython-310-aarch64-linux-gnu.so differ