diff --git a/Images/ode_always_trigger_display_source_info.png b/Images/ode_always_trigger_display_source_info.png
new file mode 100644
index 00000000..3e3e144c
Binary files /dev/null and b/Images/ode_always_trigger_display_source_info.png differ
diff --git a/Images/ode_count_trigger_display_meta.png b/Images/ode_count_trigger_display_meta.png
new file mode 100644
index 00000000..d453c224
Binary files /dev/null and b/Images/ode_count_trigger_display_meta.png differ
diff --git a/Images/ode_distance_trigger_fill_object.png b/Images/ode_distance_trigger_fill_object.png
new file mode 100644
index 00000000..e2ba79a8
Binary files /dev/null and b/Images/ode_distance_trigger_fill_object.png differ
diff --git a/Images/ode_intersection_trigger_min_max_dimensions.png b/Images/ode_intersection_trigger_min_max_dimensions.png
new file mode 100644
index 00000000..e9845f07
Binary files /dev/null and b/Images/ode_intersection_trigger_min_max_dimensions.png differ
diff --git a/Images/ode_largest_object_fill_surroundings.png b/Images/ode_largest_object_fill_surroundings.png
new file mode 100644
index 00000000..24b60138
Binary files /dev/null and b/Images/ode_largest_object_fill_surroundings.png differ
diff --git a/Images/ode_occurrence_polygon_area_inclussion_exclusion.png b/Images/ode_occurrence_polygon_area_inclussion_exclusion.png
new file mode 100644
index 00000000..6217cb48
Binary files /dev/null and b/Images/ode_occurrence_polygon_area_inclussion_exclusion.png differ
diff --git a/Makefile b/Makefile
index cf562a32..e1b7382e 100644
--- a/Makefile
+++ b/Makefile
@@ -39,7 +39,7 @@ else
endif
CXX_VERSION:=c++17
-DSL_VERSION:='L"v0.31.alpha"'
+DSL_VERSION:='L"v0.31.a.alpha"'
GLIB_VERSION:=2.0
GSTREAMER_VERSION:=1.0
diff --git a/README.md b/README.md
index f6967673..bb9d439a 100644
--- a/README.md
+++ b/README.md
@@ -50,30 +50,6 @@ $ sudo cp /usr/local/lib/librdkafka* /opt/nvidia/deepstream/deepstream-7.0/lib
```
See [Error in DeepStream 7.0 installation instructions - symlink fails to create](https://forums.developer.nvidia.com/t/error-in-deepstream-7-0-installation-instructions-symlink-fails-to-create/296026) for more information.
-## -- Release Highlights --
-
-The latest release is [v0.31.alpha](/Release%20Notes/v0.31.alpha.md)
-
-### New Component Queue management and monitoring services
-All DSL Pipeline Components use a GStream [queue plugin](https://gstreamer.freedesktop.org/documentation/coreelements/queue.html?gi-language=c) to create a new thread boundry for processing. [New services](/docs/api-component.md#component-queue-management) have been added to monitor and control the queue's leaky, current-level, max-size, and min-threshold properties. Callbacks have been added for notification of queue underrun and overrun conditions.
-
-### New Custom Sources and Sinks
-New services have been added to create [Custom Video Sources](/docs/api-source.md#custom-video-sources) and [Custom Video Sinks](/docs/api-sink.md#custom-video-sinks) Components using publicly released or proprietary GStreamer plugins.
-
-### New DSL GST Caps Objects
-GStreamer caps objects can be created to filter caps for [Custom GST Elements]() used by the [Custom Video Sources](/docs/api-source.md#custom-video-sources), [Custom Components](/docs/api-component.md#custom-components), and [Custom Video Sinks](/docs/api-sink.md#custom-video-sinks)
-
-### All Encode Sinks now support software encoding
-**IMPORTANT** this is a breaking change.
-
-The [File Sink](/docs/api-sink.md#dsl_sink_file_new), [Record Sink](/docs/api-sink.md#dsl_sink_record_new), [RTSP Server Sink](/docs/api-sink.md#dsl_sink_rtsp_server_new), and [WebRTC Sink](/docs/api-sink.md#dsl_sink_webrtc_new) now support five types of encoders:
-* two hardware; H.264, H.265.
-* and now three software; H.264, H.265, and MP4.
-
-The [RTMP Sink](/docs/api-sink.md#dsl_sink_rtmp_new) now supports software and hardware H.264 encoding.
-
-### Extensive memory leak testing has been done.
-All (minor) issues found have been resolved.
## Contributing
@@ -130,8 +106,17 @@ Come join us on [Discord](https://discord.gg/MJvY9jjpAK), an informal place to c
* [Message Broker](/docs/api-msg-broker.md)
* [Info API](/docs/api-info.md)
* [Examples](/docs/examples.md)
- * [C/C++](/docs/examples-cpp.md)
- * [Python](/docs/examples-python.md)
+ * [Basic Inference Pipelies](/docs/examples-basic-pipelines.md)
+ * [Multiple Sources, Tilers, and Demuxers](/docs/examples-sources-tiler-demuxer.md)
+ * [Advanced Inference Pipelies](/docs/examples-advanced-pipelines.md)
+ * [Smart Recording](/docs/examples-smart-recording.md)
+ * [Object Detection Event (ODE) Services](/docs/examples-ode-services.md)
+ * [Encoding Frames to JPEG](/docs/examples-encode-and-save-frame.md)
+ * [Dewarping and Segmentation](/docs/examples-dewarping-and-segmentation.md)
+ * [Dynamic Pipelines](/docs/examples-dynamic-pipelines.md)
+ * [Custom Components](/docs/examples-custom-components.md)
+ * [Working with OpenCV](/docs/examples-opencv.md)
+ * [Diagnostics and Utilites](/docs/examples-diagnaostics-and-utilities.md)
* [Tkinter Reference App](/docs/examples-tkinter.md)
* [HTML WebRTC Client](/docs/examples-webrtc-html.md)
* [Using VS Code](/docs/vscode.md)
diff --git a/Release Notes/dsl-releases.md b/Release Notes/dsl-releases.md
index 76d255be..7a89ec2f 100644
--- a/Release Notes/dsl-releases.md
+++ b/Release Notes/dsl-releases.md
@@ -2,6 +2,7 @@
| Release | Date |
| ----------------------------------------------------------- | ----------- |
+| [v0.31.a.alpha (patch)](/Release%20Notes/v0.31.a.alpha.md) | 09/16/2024 |
| [v0.31.alpha](/Release%20Notes/v0.3`.alpha.md) | 09/04/2024 |
| [v0.30.b.alpha (patch)](/Release%20Notes/v0.30.b.alpha.md) | 08/28/2024 |
| [v0.30.a.alpha (patch)](/Release%20Notes/v0.30.a.alpha.md) | 07/14/2024 |
diff --git a/Release Notes/v0.31.a.alpha.md b/Release Notes/v0.31.a.alpha.md
new file mode 100644
index 00000000..3cda83cf
--- /dev/null
+++ b/Release Notes/v0.31.a.alpha.md
@@ -0,0 +1,8 @@
+# v0.31.a.alpha (patch) Release Notes
+**Important!**
+* `v0.31.a.alpha` is a **patch** release (patch `a` for the `v0.31.alpha` release).
+* Only the documentation and examples have been updated (and improved).
+* libdsl.so has not changed in this release.
+
+## Issues closed in this release
+* Cleanup, catagorize, and document all DSL Python and C/C++ Examples [#1288](https://github.com/prominenceai/deepstream-services-library/issues/1288)
\ No newline at end of file
diff --git a/docs/examples-advanced-pipelines.md b/docs/examples-advanced-pipelines.md
new file mode 100644
index 00000000..c1c552ed
--- /dev/null
+++ b/docs/examples-advanced-pipelines.md
@@ -0,0 +1,118 @@
+# Advanced Inference Pipelies
+This page documents the following "Advance Inference Pipelines" consiting of
+* [Parallel Inference on Selective Streams](#parallel-inference-on-selective-streams)
+* [Multiple Pipelines Running in Their Own Thread](#multiple-pipelines-running-in-their-own-thread)
+* [Multiple Pipelines with Interpipe Source listening to Pipeline with InterpipeSink](#multiple-pipelines-with-interpipe-source-listening-to-pipeline-with-interpipe-sink)
+* [Single Pipeline with Interpipe Source switching between Multiple Pipelines/Sinks](#single-pipeline-with-interpipe-source-switching-between-multiple-pipelinessinks)
+
+
+
+---
+
+### Parallel Inference on Selective Streams
+
+* [`parallel_inference_on_selective_streams.py`](/examples/python/parallel_inference_on_selective_streams.py)
+* [`parallel_inference_on_selective_streams.cpp`](/examples/cpp/parallel_inference_on_selective_streams.cpp)
+
+```python
+#
+# This example shows how to use a Remuxer Component to create parallel branches,
+# each with their own Inference Components (Preprocessors, Inference Engines,
+# Trackers, for example).
+# IMPORTANT! All branches are (currently) using the same model engine and config.
+# files, which is not a valid use case. The actual inference components and
+# models to use for any specific use cases is beyond the scope of this example.
+#
+# Each Branch added to the Remuxer can specify which streams to process or
+# to process all. Use the Remuxer "branch-add-to" service to add to specific streams.
+#
+# stream_ids = [0,1]
+# dsl_remuxer_branch_add_to('my-remuxer', 'my-branch-0',
+# stream_ids, len[stream_ids])
+#
+# You can use the "branch-add" service if adding to all streams
+#
+# dsl_remuxer_branch_add('my-remuxer', 'my-branch-0')
+#
+# In this example, 4 RTSP Sources are added to the Pipeline:
+# - branch-1 will process streams [0,1]
+# - branch-2 will process streams [1,2]
+# - branch-3 will process streams [0,2,3]
+#
+# Three ODE Instance Triggers are created to trigger on new object instances
+# events (i.e. new tracker ids). Each is filtering on a unique class-i
+# (vehicle, person, and bicycle).
+#
+# The ODE Triggers are added to an ODE Handler which is added to the src-pad
+# (output) of the Remuxer.
+#
+# A single ODE Print Action is created and added to each Trigger (shared action).
+# Using multiple Print Actions running in parallel -- each writing to the same
+# stdout buffer -- will result in the printed data appearing interlaced. A single
+# Action with an internal mutex will protect from stdout buffer reentrancy.
+#
+
+```
+
+
+
+---
+
+### Multiple Pipelines Running in Their Own Thread
+
+* [`multiple_pipelines.py`](/examples/python/multiple_pipelines.py)
+* [`multiple_pipelines.cpp`](/examples/cpp/multiple_pipelines.cpp)
+
+```python
+#
+# This example demonstrates how to run multple Pipelines, each in their own
+# thread, and each with their own main-context and main-loop.
+#
+# After creating and starting each Pipelines, the script joins each of the
+# threads waiting for them to complete - either by EOS message, 'Q' key, or
+# Delete Window.
+#
+```
+
+
+
+---
+
+### Multiple Pipelines with Interpipe Source listening to Pipeline with Interpipe Sink
+
+* [`interpipe_multiple_pipelines_listening_to_single_sink.py`](/examples/python/interpipe_multiple_pipelines_listening_to_single_sink.py)
+* [`interpipe_multiple_pipelines_listening_to_single_sink.cpp`](/examples/cpp/interpipe_multiple_pipelines_listening_to_single_sink.cpp)
+
+```python
+#
+# This script demonstrates how to run multple Pipelines, each with an Interpipe
+# Source, both listening to the same Interpipe Sink.
+#
+# A single Player is created with a File Source and Interpipe Sink. Two Inference
+# Pipelines are created to listen to the single Player - shared input stream.
+# The two Pipelines can be created with different configs, models, and/or Trackers
+# for side-by-side comparison. Both Pipelines run in their own main-loop with their
+# own main-context, and have their own Window Sink for viewing and external control.
+#
+```
+
+
+---
+
+### Single Pipeline with Interpipe Source switching between Multiple Pipelines/Sinks
+
+* [`interpipe_single_pipeline_dynamic_switching_between_multiple_sinks.py`](/examples/python/interpipe_single_pipeline_dynamic_switching_between_multiple_sinks.py)
+* [`interpipe_single_pipeline_dynamic_switching_between_multiple_sinks.cpp`](/examples/cpp/interpipe_single_pipeline_dynamic_switching_between_multiple_sinks.cpp)
+
+```python
+# ------------------------------------------------------------------------------------
+# This example demonstrates interpipe dynamic switching. Four DSL Players
+# are created, each with a File Source and Interpipe Sink. A single
+# inference Pipeline with an Interpipe Source is created as the single listener
+#
+# The Interpipe Source's "listen_to" setting is updated based on keyboard input.
+# The xwindow_key_event_handler (see below) is added to the Pipeline's Window Sink.
+# The handler, on key release, sets the "listen_to" setting to the Interpipe Sink
+# name that corresponds to the key value - 1 through 4.
+```
+
diff --git a/docs/examples-basic-pipelines.md b/docs/examples-basic-pipelines.md
new file mode 100644
index 00000000..36f9962b
--- /dev/null
+++ b/docs/examples-basic-pipelines.md
@@ -0,0 +1,436 @@
+# Basic Inference Pipelines with different Sources and Sinks
+This page documents the following "Basic Inference Pipelines" consiting of
+* [CSI Source, Primary GIE, OSD, and 3D Window Sink](#csi-source-primary-gie-osd-and-3d-window-sink)
+* [File Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink, and File Sink](#file-source-primary-gie-iou-tracker-osd-egl-window-sink-and-file-sink)
+* [File Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink, and RTSP Sink](#file-source-primary-gie-iou-tracker-osd-egl-window-sink-and-rtsp-sink)
+* [File Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink, and V4L2 Sink](#file-source-primary-gie-iou-tracker-osd-egl-window-sink-and-v4l2-sink)
+* [RTSP Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink](#rtsp-source-primary-gie-iou-tracker-osd-egl-window-sink)
+* [HTTP Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink](#http-source-primary-gie-iou-tracker-osd-egl-window-sink)
+* [File Source, Preprocessor, Primary GIE, IOU Tracker, OSD, EGL Window Sink](#file-source-preprocessor-primary-gie-iou-tracker-osd-egl-window-sink)
+* [File Source, Primary TIS, DSF Tracker, OSD, EGL Window Sink](#file-source-primary-tis-dsf-tracker-osd-egl-window-sink)
+* [File Source, Primary TIS, IOU Tracker, OSD, EGL Window Sink](#file-source-primary-tis-iou-tracker-osd-egl-window-sink)
+* [File Source, Primary TIS, IOU Tracker, 2 Secondary TIS, OSD, EGL Window Sink](#file-source-primary-tis-iou-tracker-2-secondary-tis-osd-egl-window-sink)
+* [Image Source, Primary GIE, OSD, and EGL Window Sink](#image-source-primary-gie-osd-and-egl-window-sink)
+* [URI Source, Primary GIE, IOU Tracker, and App Sink](#uri-source-primary-gie-iou-tracker-and-app-sink)
+* [V4L2 Source, Primary GIE, IOU Tracker, OSD, and EGL Window Sink](#v4l2-source-primary-gie-iou-tracker-osd-and-egl-window-sink)
+* [App Source, Primary TIE, IOU Tracker, OSD, and EGL Window Sink](#app-source-primary-tie-iou-tracker-osd-and-egl-window-sink)
+
+---
+
+### CSI Source, Primary GIE, OSD, and 3D Window Sink
+
+* [`1csi_pgie_osd_3dsink.py`](/examples/python/1csi_pgie_osd_3dsink.py)
+* cpp example is still to be done
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - CSI Source
+# - Primary GST Inference Engine (PGIE)
+# - On-Screen Display
+# - 3D Sink
+# ...and how to add them to a new Pipeline and play.
+#
+# IMPORTANT! this examples uses a CSI Camera Source and 3D Sink - Jetson only!
+#
+```
+
+
+---
+
+### File Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink, and File Sink
+
+* [`1file_pgie_iou_tracker_osd_window_file.py`](/examples/python/1file_pgie_iou_tracker_osd_window_file.py)
+* [`1file_pgie_iou_tracker_osd_window_file.cpp`](/examples/cpp/1file_pgie_iou_tracker_osd_window_file.cpp)
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - File Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display (OSD)
+# - Window Sink
+# - File Sink to encode and save the stream to file.
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+### File Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink, and RTSP Sink
+
+* [`1file_pgie_iou_tracker_osd_window_rtsp.py`](/examples/python/1file_pgie_iou_tracker_osd_window_rtsp.py)
+* [`1file_pgie_iou_tracker_osd_window_rtsp.cpp`](/examples/cpp/1file_pgie_iou_tracker_osd_window_rtsp.cpp)
+
+```python
+#
+# This simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - A File Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+# - RTSP Sink
+# ...and how to add them to a new Pipeline and play.
+#
+# The example registers handler callback functions for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+### File Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink, and V4L2 Sink
+
+* [`1file_pgie_iou_tracker_osd_window_v4l2.py`](/examples/python/1file_pgie_iou_tracker_osd_window_v4l2.py)
+* [`1file_pgie_iou_tracker_osd_window_v4l2.cpp`](/examples/cpp/1file_pgie_iou_tracker_osd_window_v4l2.cpp)
+
+```python
+#
+# This simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - A File Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+# - V4L2 Sink
+# ...and how to add them to a new Pipeline and play.
+#
+# The V4L2 Sink is used to display video to v4l2 video devices.
+#
+# V4L2 Loopback can be used to create "virtual video devices". Normal (v4l2)
+# applications will read these devices as if they were ordinary video devices.
+# See: https://github.com/umlaeute/v4l2loopback for more information.
+#
+# You can install v4l2loopback with
+# $ sudo apt-get install v4l2loopback-dkms
+#
+# Run the following to setup '/dev/video3'
+# $ sudo modprobe v4l2loopback video_nr=3
+#
+# When the script is running, you can use the following GStreamer launch
+# command to test the loopback
+# $ gst-launch-1.0 v4l2src device=/dev/video3 ! videoconvert ! xvimagesink
+#
+# The example registers handler callback functions for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+### RTSP Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink
+
+* [`1rtsp_pgie_dcf_tracker_osd_window.py`](/examples/python/1rtsp_pgie_dcf_tracker_osd_window.py)
+* [`1rtsp_pgie_dcf_tracker_osd_window.cpp`](/examples/cpp/1rtsp_pgie_dcf_tracker_osd_window.cpp)
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - RTSP Source
+# - Primary GST Inference Engine (PGIE)
+# - DCF Tracker
+# - On-Screen Display (OSD)
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - error-message events
+# - Pipeline change-of-state events
+# - RTSP Source change-of-state events.
+#
+# IMPORTANT! The error-message-handler callback fucntion will stop the Pipeline
+# and main-loop, and then exit. If the error condition is due to a camera
+# connection failure, the application could choose to let the RTSP Source's
+# connection manager periodically reattempt connection for some length of time.
+#
+```
+
+
+---
+
+### HTTP Source, Primary GIE, IOU Tracker, OSD, EGL Window Sink
+
+* [`1uri_http_pgie_iou_tracker_osd_window.py`](/examples/python/1uri_http_pgie_iou_tracker_osd_window.py)
+* [`1uri_http_pgie_iou_tracker_osd_window.cpp`](/examples/cpp/1uri_http_pgie_iou_tracker_osd_window.cpp)
+
+```python
+################################################################################
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - HTTP URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display (OSD)
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - component-buffering messages
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+# IMPORTANT! The URI Source will send messages on the Pipeline bus when
+# buffering is in progress. The buffering_message_handler callback is
+# added to the Pipeline to be called with every buffer message received.
+# The handler callback is required to pause the Pipeline while buffering
+# is in progress.
+#
+# The callback is called with the percentage of buffering done, with
+# 100% indicating that buffering is complete.
+#
+################################################################################
+```
+
+
+
+---
+
+### File Source, Preprocessor, Primary GIE, IOU Tracker, OSD, EGL Window Sink
+
+* [`1file_preproc_pgie_iou_tracker_osd_window.py`](/examples/python/1file_preproc_pgie_iou_tracker_osd_window.py)
+* [`1file_preproc_pgie_iou_tracker_osd_window.cpp`](/examples/cpp/1file_preproc_pgie_iou_tracker_osd_window.cpp)
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - URI Source
+# - Preprocessor
+# - Primary GIE
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# Specific services must be called for the PGIE to be able to receive tensor-meta
+# buffers from the Preprocessor component.
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+### File Source, Primary TIS, DSF Tracker, OSD, EGL Window Sink
+
+* [`1file_ptis_dcf_tracker_osd_window.py`](/examples/python/1file_ptis_dcf_tracker_osd_window.py)
+* cpp example is still to be done
+
+```python
+#
+# The example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - File Source
+# - Primary Triton Inference Server (PTIS)
+# - NcDCF Low Level Tracker
+# - On-Screen Display
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+### File Source, Primary TIS, IOU Tracker, OSD, EGL Window Sink
+
+* [`1file_ptis_iou_tracker_osd_window.py`](/examples/python/1file_ptis_iou_tracker_osd_window.py)
+* [`1file_ptis_iou_tracker_osd_window.cpp`](/examples/cpp/1file_ptis_iou_tracker_osd_window.cpp)
+
+```python
+#
+# The example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - File Source
+# - Primary Triton Inference Server (PTIS)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+### File Source, Primary TIS, IOU Tracker, 2 Secondary TIS, OSD, EGL Window Sink
+
+* [`1file_ptis_iou_tracker_2stis_osd_window.py`](/examples/python/1file_ptis_iou_tracker_2stis_osd_window.py)
+* cpp example is still to be done
+
+```python
+#
+# The example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - File Source
+# - Primary Triton Inference Server (PTIS)
+# - 2 Secondary Triton Inference Servers(STIS)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+### Image Source, Primary GIE, OSD, and EGL Window Sink
+
+* [`1image_jpeg_pgie_osd_window.py`](/examples/python/1image_jpeg_pgie_osd_window.py)
+* cpp example is still to be done
+
+```python
+#
+# The example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - Image Source - single image to EOS
+# - Primary GST Inference Engine (PGIE)
+# - On-Screen Display
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+### URI Source, Primary GIE, IOU Tracker, and App Sink
+
+* [`1uri_file_pgie_iou_tracker_app_sink.py`](/examples/python/1uri_file_pgie_iou_tracker_app_sink.py)
+* cpp example is still to be done
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - APP Sink
+# ...and how to add them to a new Pipeline and play
+#
+# A "new_buffer_handler_cb" is added to the APP Sink to process the frame
+# and object meta-data for each buffer received
+#
+```
+
+
+---
+
+### V4L2 Source, Primary GIE, IOU Tracker, OSD, and EGL Window Sink
+
+* [`1v4l2_pgie_iou_tracker_osd_window.py`](/examples/python/1v4l2_pgie_iou_tracker_osd_window.py)
+* [`1v4l2_pgie_iou_tracker_osd_window.cpp`](/examples/cpp/1v4l2_pgie_iou_tracker_osd_window.cpp)
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - V4L2 Source - Web Camera
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+#
+# The key-release handler function will update the V4L2 device picture settings
+# based on the key value as follows during runtime.
+# * brightness - or more correctly the black level.
+# enter 'B' to increase, 'b' to decrease
+# * contrast - color contrast setting or luma gain.
+# enter 'C' to increase, 'c' to decrease
+# * hue - color hue or color balence.
+# enter 'H' to increase, 'h' to decrease
+#
+# The Picture Settings are all integer values, range
+```
+
+---
+
+### App Source, Primary TIE, IOU Tracker, OSD, and EGL Window Sink
+
+* Python example is still to be done
+* [`raw_i420_app_src_ptis_tracker_osd_window.cpp`](/examples/cpp/raw_i420_app_src_ptis_tracker_osd_window.cpp)
+
+```python
+#
+# This example illustrates how to push raw video buffers to a DSL Pipeline
+# using an App Source component. The example application adds the following
+# client handlers to control the input of raw buffers to the App Source
+# * need_data_handler - called when the App Source needs data to process
+# * enough_data_handler - called when the App Source has enough data to process
+#
+# The client handlers add/remove a callback function to read, map, and push data
+# to the App Source called "read_and_push_data".
+#
+# The raw video file used with this example is created by executing the following
+# gst-launch-1.0 command.
+#
+# gst-launch-1.0 uridecodebin \
+# uri=file:///opt/nvidia/deepstream/deepstream/samples/streams/sample_720p.mp4 \
+# ! nvvideoconvert ! 'video/x-raw, format=I420, width=1280, height=720' \
+# ! filesink location=./sample_720p.i420
+#
+```
diff --git a/docs/examples-cpp.md b/docs/examples-cpp.md
deleted file mode 100644
index eb8a4241..00000000
--- a/docs/examples-cpp.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# C/C++ Examples
-The following C/C++ examples are available under the `/examples/cpp`. The same examples exist for Python under `/examples/python`
-
-### [1file_ptis_ktl_osd_window.cpp](/examples/cpp/1file_ptis_ktl_osd_window.cpp)
-A simple pipeline with a single `File Source`, `Primary Triton Inference Server`, `KTL Tracker`, `On-Screen Display`, and `Window Sink`. The example adds a number of Client callbacks to the Pipeline to handle `XWindow KeyRelease`, `XWindow Delete`, `Pipeline state change`, and `End-of-Stream (EOS)`.
-
-### [ode_occurrence_4rtsp_start_record_tap_action.cpp](/examples/cpp/ode_occurrence_4rtsp_start_record_tap_action.cpp)
-A more complete example with a variable number of `RTSP Sources`, each with a `Record Tap` for smart recording. The Pipeline is assembled with a `Primary GST Inference Engine`, `IOU Tracker`, `2D Tiler`, `On-Screen Display`, `Window Sink`, and most importantly a `Object Detection Event (ODE) PPH Handler`. The following `ODE Triggers` with `ODE Actions` are added to the ODE Handler for each RTSP Source:
-* `Instance Trigger` - to trigger on new instances of a Person with a unique tracking id with a limit of one.
- * `Start Recording Action` - to start a new smart recording session.
-* `Always Trigger` - to trigger on every frame when enabled (enabled/disabled in an `On Recording Event` callback)
- * `Display Meta Action` - to add a recording in progress indicator
- * `Display Types` - used as a `REC ON` indicator
-
-The example adds a number of Client callbacks to the Pipeline to handle `XWindow KeyRelease`, `XWindow Delete`, `Pipeline state change`, and `End-of-Stream (EOS)`.
-
-### [player_play_all_mp4_files_found.cpp](/examples/cpp/player_play_all_mp4_files_found.cpp)
-A simple example of how to use a `Video Render Player`, a type of simplified GST Pipeline with a single `File Source` and `Window Sink`, to play all recorded files in a specified directory.
-
-### [rtsp_player_to_test_connections.cpp](/examples/cpp/rtsp_player_to_test_connections.cpp)
-A simple `Player` with an `RTSP Source` and `Window Sink` that can be very useful for testing your RTSP URI's without building a pipeline.
-
----
-
-In addition to the above examples, all DSL API testing is done against the extern C API. The following test files may be useful as examples.
-* [DslPipelinePlayComponentsTest.cpp](/test/api/DslPipelinePlayComponentsTest.cpp)
-* [DslOdeBehaviorTest.cpp](/test/api/DslOdeBehaviorTest.cpp)
-* [DslPipelinePlayTrackerTest.cpp](/test/api/DslPipelinePlayTrackerTest.cpp)
diff --git a/docs/examples-custom-components.md b/docs/examples-custom-components.md
new file mode 100644
index 00000000..17e569b5
--- /dev/null
+++ b/docs/examples-custom-components.md
@@ -0,0 +1,128 @@
+# Pipelines with Custom Sources, Components, and Sinks
+This page documents the following examples:
+* [Pipeline with Custom Source Component](#pipeline-with-custom-source-component)
+* [Pipeline with Custom Component - non Source or Sink](#pipeline-with-custom-component---non-source-or-sink)
+* [Pipeline with Custom Sink Component](#pipeline-with-custom-sink-component)
+
+
+
+---
+
+### Pipeline with Custom Source Component
+
+* [`pipeline_with_custom_source.py`](/examples/python/pipeline_with_custom_source.py)
+* [`pipeline_with_custom_source.cpp`](/examples/cpp/pipeline_with_custom_source.cpp)
+
+```python
+#
+# This example demonstrates how to create a custom DSL Source Component
+# using two GStreamer (GST) Elements created from two GST Plugins:
+# 1. 'videotestsrc' as the source element.
+# 2. 'capsfilter' to limit the video from the videotestsrc to
+# 'video/x-raw, framerate=15/1, width=1280, height=720'
+#
+# Elements are constructed from plugins installed with GStreamer or
+# using your own proprietary plugin with a call to
+#
+# dsl_gst_element_new('my-element', 'my-plugin-factory-name' )
+#
+# Multiple elements can be added to a Custom Source on creation be calling
+#
+# dsl_source_custom_new_element_add_many('my-custom-source',
+# ['my-element-1', 'my-element-2', None])
+#
+# As with all DSL Video Sources, the Custom Souce will also include the
+# standard buffer-out-elements (queue, nvvideconvert, and capsfilter).
+# The Source in this example will be linked as follows:
+#
+# videotestscr->capsfilter->queue->nvvideconvert->capsfilter
+#
+# See the GST and Source API reference sections for more information
+#
+# https://github.com/prominenceai/deepstream-services-library/tree/master/docs/api-gst.md
+# https://github.com/prominenceai/deepstream-services-library/tree/master/docs/api-source.md
+#
+```
+
+
+---
+
+### Pipeline with Custom Component - non Source or Sink
+
+* [`pipeline_with_custom_component.py`](/examples/python/pipeline_with_custom_component.py)
+* [`pipeline_with_custom_component.cpp`](/examples/cpp/pipeline_with_custom_component.cpp)
+
+```python
+#
+# The example demonstrates how to create a custom DSL Pipeline Component with
+# a custom GStreamer (GST) Element.
+#
+# Elements are constructed from plugins installed with GStreamer or
+# using your own proprietary -- with a call to
+#
+# dsl_gst_element_new('my-element', 'my-plugin-factory-name' )
+#
+# IMPORTANT! All DSL Pipeline Components, intrinsic and custom, include
+# a queue element to create a new thread boundary for the component's element(s)
+# to process in.
+#
+# This example creates a simple Custom Component with two elements
+# 1. The built-in 'queue' plugin - to create a new thread boundary.
+# 2. An 'identity' plugin - a GST debug plugin to mimic our proprietary element.
+#
+# A single GST Element can be added to the Component on creation by calling
+#
+# dsl_component_custom_new_element_add('my-custom-component',
+# 'my-element')
+#
+# Multiple elements can be added to a Component on creation be calling
+#
+# dsl_component_custom_new_element_add_many('my-bin',
+# ['my-element-1', 'my-element-2', None])
+#
+# https://github.com/prominenceai/deepstream-services-library/tree/master/docs/api-gst.md
+# https://github.com/prominenceai/deepstream-services-library/tree/master/docs/api-component.md
+#
+```
+
+
+---
+
+### Pipeline with Custom Sink Component
+
+* [`pipeline_with_custom_sink.py`](/examples/python/pipeline_with_custom_source.py)
+* [`pipeline_with_custom_sink.cpp`](/examples/cpp/pipeline_with_custom_sink.cpp)
+
+```python
+#
+# The example demonstrates how to create a custom DSL Sink Component with
+# using custom GStreamer (GST) Elements.
+#
+# Elements are constructed from plugins installed with GStreamer or
+# using your own proprietary with a call to
+#
+# dsl_gst_element_new('my-element', 'my-plugin-factory-name' )
+#
+# IMPORTANT! All DSL Pipeline Components, intrinsic and custom, include
+# a queue element to create a new thread boundary for the component's element(s)
+# to process in.
+#
+# This example creates a simple Custom Sink with four elements in total
+# 1. The built-in 'queue' element - to create a new thread boundary.
+# 2. An 'nvvideoconvert' element - to convert the buffer from
+# 'video/x-raw(memory:NVMM)' to 'video/x-raw'
+# 3. A 'capsfilter' plugin - to filter the 'nvvideoconvert' caps to
+# 'video/x-raw'
+# 4. A 'glimagesink' plugin - the actual Sink element for this Sink component.
+#
+# Multiple elements can be added to a Custom Sink on creation be calling
+#
+# dsl_sink_custom_new_element_add_many('my-bin',
+# ['my-element-1', 'my-element-2', 'my-element-3', None])
+#
+# https://github.com/prominenceai/deepstream-services-library/tree/master/docs/api-gst.md
+# https://github.com/prominenceai/deepstream-services-library/tree/master/docs/api-sink.md
+#
+```
+
+
diff --git a/docs/examples-dewarping-and-segmentation.md b/docs/examples-dewarping-and-segmentation.md
new file mode 100644
index 00000000..bb37da87
--- /dev/null
+++ b/docs/examples-dewarping-and-segmentation.md
@@ -0,0 +1,114 @@
+# Video Dewarping and Segmentation Viewing
+This page documents the following Segmentation examples:
+* [360 Degree Video Dewarping](#360-degree-video-dewarping)
+* [Perspective Video Dewarping](#perspective-video-dewarping)
+* [Industrial Segmentation and Viewing](#industrial-segmentation-and-viewing)
+* [Semantic Segmentation and Viewing](#semantic-segmentation-and-viewing)
+
+
+
+---
+
+### 360 Degree Video Dewarping
+
+* [`video_dewarper_360.py`](/examples/python/video_dewarper_360.py)
+* cpp example is still to be done
+
+```python
+# This example shows the use of a Video Dewarper to dewarp a 360d camera stream
+# - recorded from a 360d camera and provided by NVIDIA as a sample stream.
+#
+# The Dewarper component is created with the following parameters
+# - a config "file config_dwarper_txt" which tailors this 360d camera
+# multi-surface use-case.
+# - and a camera-id which refers to the first column of the CSV files
+# (i.e. csv_files/nvaisle_2M.csv & csv_files/nvspot_2M.csv).
+# The dewarping parameters for the given camera are read from CSV
+# files and used to generate dewarp surfaces (i.e. multiple aisle
+# and spot surface) from 360d input video stream.
+# All files are located under:
+# /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-dewarper-test/
+```
+
+
+---
+
+### Perspective Video Dewarping
+
+* [`video_dewarper_perspective.py`](/examples/python/video_dewarper_perspective.py)
+* cpp example is still to be done
+
+```python
+#
+# This example shows the use of a Video Dewarper to dewarp a perspective view.
+#
+# The Dewarper component is created with the following parameters:
+# - a config "config_dewarper_perspective.txt" which defines all dewarping
+# parameters - i.e. the csv files are not used for this example.
+# - and a camera-id which is NOT USED! Perspecitve dewarping requires that all
+# parameters be defined in the config file.
+# All files are located under:
+# /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-dewarper-test/
+#
+```
+
+
+---
+
+### Industrial Segmentation and Viewing
+
+* [`segmentation_industrial.py`](/examples/python/segmentation_industrial.py)
+* cpp example is still to be done
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - URI Source to read a jpeg image file
+# - Primary GST Inference Engine (PGIE)
+# - Segmentation Visualizer
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+#
+# NOTE: The Primary GST Inference engine is configured for Industrial Segmentation.
+# The NVIDIA provided PGIE configuration file can be found at
+# /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-segmentation-test/
+#
+# The URI Source will push a single frame followed by an End of File (EOF) event.
+#
+```
+
+
+
+---
+
+### Semantic Segmentation and Viewing
+
+* [`segmentation_semantic.py`](/examples/python/segmentation_semantic.py)
+* cpp example is still to be done
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - URI Source to read a jpeg image file
+# - Primary GST Inference Engine (PGIE)
+# - Segmentation Visualizer
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+#
+# NOTE: The Primary GST Inference engine is configured for Semantic Segmentation.
+# The NVIDIA provided PGIE configuration file can be found at
+# /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-segmentation-test/
+#
+# The URI Source will push a single frame followed by an End of File (EOF) event.
+#
+```
diff --git a/docs/examples-diagnaostics-and-utilities.md b/docs/examples-diagnaostics-and-utilities.md
new file mode 100644
index 00000000..b38d1825
--- /dev/null
+++ b/docs/examples-diagnaostics-and-utilities.md
@@ -0,0 +1,125 @@
+# Pipeline Diagnostics and Utilities
+This page documents the following examples:
+* [Pipeline with Source Meter Pad Probe Handler and Component Queue Management](#pipeline-with-source-meter-pad-probe-handler-and-component-queue-management)
+* [Using a Simple DSL Player to test an RTSP Source Connection](#using-a-simple-dsl-player-to-test-an-rtsp-source-connection)
+* [Running Inference on all MP4 files in a Folder](#running-inference-on-all-mp4-files-in-a-folder)
+
+
+
+---
+
+### Pipeline with Source Meter Pad Probe Handler and Component Queue Management
+
+* [`8uri_file_pph_meter_performace_reporting.py`](/examples/python/8uri_file_pph_meter_performace_reporting.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demostrates how to use a Source Meter Pad Probe Handler (PPH)
+# that will measure the Pipeline's throughput for each Source - while monitoring
+# the depth of every component's Queue.
+#
+# The Meter PPH is added to the sink (input) pad of the Tiler before tha batched
+# stream is converted into a single stream as a 2D composite of all Sources.
+#
+# The "meter_pph_handler" callback added to the Meter PPH will handle writing
+# the Avg Session FPS and the Avg Interval FPS measurements to the console.
+# #
+# The Key-released-handler callback (below) will disable the meter when pausing
+# the Pipeline, and # re-enable measurements when the Pipeline is resumed.
+#
+# Note: Session averages are reset each time the Meter is disabled and
+# then re-enabled.
+#
+# The callback, called once per second as defined during Meter construction,
+# is also responsible for polling the components for their queue depths - i.e
+# using the "dsl_component_queue_current_level_print_many" service.
+#
+# Additionally, a Queue Overrun Listener is added to each of the components to
+# be notified on the event of a queue-overrun.
+#
+# https://github.com/prominenceai/deepstream-services-library/blob/master/docs/api-component.md#component-queue-management
+#
+```
+
+Example of the metrics that are printed every second.
+```
+FPS 0 (AVG) FPS 1 (AVG) FPS 2 (AVG) FPS 3 (AVG) FPS 4 (AVG) FPS 5 (AVG) FPS 6 (AVG) FPS 7 (AVG)
+30.00 (30.99) 30.00 (30.99) 30.00 (30.99) 30.00 (30.99) 30.00 (30.99) 30.00 (30.99) 30.00 (30.99) 30.00 (30.99)
+
+'current-level-buffers' = 0/200 for component 'uri-source-0'
+'current-level-buffers' = 0/200 for component 'uri-source-1'
+'current-level-buffers' = 0/200 for component 'uri-source-2'
+'current-level-buffers' = 0/200 for component 'uri-source-3'
+'current-level-buffers' = 0/200 for component 'uri-source-4'
+'current-level-buffers' = 0/200 for component 'uri-source-5'
+'current-level-buffers' = 0/200 for component 'uri-source-6'
+'current-level-buffers' = 0/200 for component 'uri-source-7'
+'current-level-buffers' = 0/200 for component 'primary-gie'
+'current-level-buffers' = 0/200 for component 'iou-tracker'
+'current-level-buffers' = 3/200 for component 'tiler'
+'current-level-buffers' = 3/200 for component 'on-screen-display'
+'current-level-buffers' = 3/200 for component 'window-sink'
+```
+
+
+
+---
+
+### Using a Simple DSL Player to test an RTSP Source Connection
+
+* [`rtsp_player_to_test_connections.py`](/examples/python/rtsp_player_to_test_connections.py)
+* cpp example is still to be done
+
+```python
+#
+# This example can be used to test your RTSP Source connection. It uses a simple
+# DSL Player with a single RTSP Source and Window Sink:
+#
+# There two example camera URI's below. One for AMCREST and one for HIKVISION.
+# update one of the URI's with your username and password, or add your own
+# URI format as needed.
+#
+# Ensure that the RTSP Source constructor is using the correct URI.
+#
+# The example registers handler callback functions to be notified of:
+# - key-release events
+# - delete-window events
+# - RTSP Source change-of-state events
+#
+```
+
+
+---
+
+### Running Inference on all MP4 files in a Folder
+
+* [`process_all_mp4_files_in_folder.py`](/examples/python/process_all_mp4_files_in_folder.py)
+* cpp example is still to be done
+
+```python
+#
+# This simple example demonstrates how to process (infer-on) all .mp4 files
+# in a given folder.
+#
+# The inference Pipeline is built with the following components:
+# - URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display (OSD)
+# - Window Sink
+#
+# A Custom Pad-Probe-Handler is added to the Sink-Pad of the OSD
+# to process the frame and object meta-data for each buffer received
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events.
+#
+# IMPORTANT! it is the end-of-stream (EOS) listener "eos_event_listener"
+# that stops the Pipeline on EOS, sets the URI to the next file in
+# the list, and starts the Pipeline again.
+#
+```
diff --git a/docs/examples-dynamic-pipelines.md b/docs/examples-dynamic-pipelines.md
new file mode 100644
index 00000000..01f7af13
--- /dev/null
+++ b/docs/examples-dynamic-pipelines.md
@@ -0,0 +1,79 @@
+# Dynamic Pipelines
+This page documents the following examples:
+* [Dynamically Add/Remove Sources to/from a Pipeline with a Tiler and Window Sink](#dynamically-addremove-sources-tofrom-a-pipeline-with-a-tiler-and-window-sink)
+* [Dynamically Move a Branch from One Demuxer Stream to Another](#dynamically-move-a-branch-from-one-demuxer-stream-to-another)
+
+
+
+---
+
+### Dynamically Add/Remove Sources to/from a Pipeline with a Tiler and Window Sink
+
+* [`dynamically_add_remove_sources_with_tiler_window_sink.py`](/examples/python/dynamically_add_remove_sources_with_tiler_window_sink.py)
+* [`dynamically_add_remove_sources_with_tiler_window_sink.cpp`](/examples/cpp/dynamically_add_remove_sources_with_tiler_window_sink.cpp)
+
+```python
+#
+# This example shows how to dynamically add and remove Source components
+# while the Pipeline is playing. The Pipeline must have at least once source
+# while playing. The Pipeline consists of:
+# - A variable number of File Sources. The Source are created/added and
+# removed/deleted on user key-input.
+# - The Pipeline's built-in streammuxer muxes the streams into a
+# batched stream as input to the Inference Engine.
+# - Primary GST Inference Engine (PGIE).
+# - IOU Tracker.
+# - Multi-stream 2D Tiler - created with rows/cols to support max-sources.
+# - On-Screen Display (OSD)
+# - Window Sink - with window-delete and key-release event handlers.
+#
+# A Source component is created and added to the Pipeline by pressing the
+# "+" key which calls the following services:
+#
+# dsl_source_uri_new(source_name, uri_h265, True, 0, 0)
+# dsl_pipeline_component_add('pipeline', source_name)
+#
+# A Source component (last added) is removed from the Pipeline and deleted by
+# pressing the "-" key which calls the following services
+#
+# dsl_pipeline_component_remove('pipeline', source_name)
+# dsl_component_delete(source_name)
+#
+```
+
+
+---
+
+### Dynamically Move a Branch from One Demuxer Stream to Another
+
+* [`dynamically_move_branch_from_demuxer_stream_to_stream.py`](/examples/python/dynamically_move_branch_from_demuxer_stream_to_stream.py)
+* [`dynamically_move_branch_from_demuxer_stream_to_stream.cpp`](/examples/cpp/dynamically_move_branch_from_demuxer_stream_to_stream.cpp)
+
+```python
+
+#
+# This example shows how to use a single dynamic demuxer branch with a
+# multi-source Pipeline. The Pipeline trunk consists of:
+# - 5 Streaming Images Sources - each streams a single image at a given
+# frame-rate with a number overlayed representing the stream-id.
+# - The Pipeline's built-in streammuxer muxes the streams into a
+# batched stream as input to the Inference Engine.
+# - Primary GST Inference Engine (PGIE).
+# - IOU Tracker.
+#
+# The dynamic branch will consist of:
+# - On-Screen Display (OSD)
+# - Window Sink - with window-delete and key-release event handlers.
+#
+# The branch is added to one of the Streams when the Pipeline is constructed
+# by calling:
+#
+# dsl_tee_demuxer_branch_add_to('demuxer', 'branch-0', stream_id)
+#
+# Once the Pipeline is playing, the example uses a simple periodic timer to
+# call a callback function which advances/cycles the current stream_id
+# variable and moves the branch by calling.
+#
+# dsl_tee_demuxer_branch_move_to('demuxer', 'branch-0', stream_id)
+#
+```
diff --git a/docs/examples-encode-and-save-frame.md b/docs/examples-encode-and-save-frame.md
new file mode 100644
index 00000000..1dc0e06b
--- /dev/null
+++ b/docs/examples-encode-and-save-frame.md
@@ -0,0 +1,110 @@
+# Different Methods of Encoding and Saving a Frame to JPEG File
+This page documents the following examples:
+* [Encode and Save Frame using Capture Action/Sink Scheduled from a Custom PPH](#encode-and-save-frame-using-capture-actionsink-scheduled-from-a-custom-pph)
+* [Encode and Save Frame using Capture Action/Sink on User or Application Demand](#encode-and-save-frame-using-capture-actionsink-on-user-or-application-demand)
+* [Encode and Save Frames periodically using Multi-Image Sink](#encode-and-save-frames-periodically-using-multi-image-sink)
+
+**Note:** There are other Encoding/Saviing Frame examples documented under
+* [Object Detection Event (ODE) Services](/docs/examples-ode-services.md)
+* [Working with OpenCV](/docs/examples-opencv.md)
+
+
+
+
+---
+### Encode and Save Frame using Capture Action/Sink Scheduled from a Custom PPH
+
+* [`encode_and_save_frame_to_jpeg_from_custom_pph.py`](/examples/python/encode_and_save_frame_to_jpeg_from_custom_pph.py)
+* [`encode_and_save_frame_to_jpeg_from_custom_pph.cpp`](/examples/cpp/encode_and_save_frame_to_jpeg_from_custom_pph.cpp)
+
+```python
+#
+# This example demonstrates the use of a Frame-Capture Sink to encode and
+# save video frames to JPEG files scheduled from a Custom Pad Probe Handler (PPH).
+#
+# An ODE Frame-Capture Action is provided to The Frame-Capture Sink on creation.
+# A client "capture_complete_listener" is added to the the Action to be notified
+# when each new file is saved (the ODE Action performs the actual frame-capture).
+#
+# Child Players (to play the captured image) and Mailers (to mail the image) can
+# be added to the ODE Frame-Capture action as well (not shown).
+#
+# A Custom Pad Probe Handler (PPH) is added to the sink-pad of the OSD component
+# to process every buffer flowing over the pad by:
+# - Retrieving the batch-metadata and its list of frame metadata structures
+# (only one frame per batched-buffer with 1 Source)
+# - Retrieving the list of object metadata structures from the frame metadata.
+# - Iterating through the list of objects looking for the first occurrence of
+# a bicycle.
+# - If detected, the current frame-number is schedule to be captured by the
+# Frame-Capture Sink using its Frame-Capture Action.
+#
+# dsl_sink_frame_capture_schedule('frame-capture-sink',
+# frame_meta.frame_num)
+#
+# Note: The Custom PPH will schedule every frame with a bicycle to be captured!
+#
+# IMPORT All captured frames are copied and buffered in the Sink's processing
+# thread. The encoding and saving of each buffered frame is done in the
+# g-idle-thread, therefore, the capture-complete notification is asynchronous.
+#
+```
+
+
+---
+
+### Encode and Save Frame using Capture Action/Sink on User or Application Demand
+
+* [`encode_and_save_frame_to_jpeg_on_viewer_demand.py`](/examples/python/encode_and_save_frame_to_jpeg_on_viewer_demand.py)
+* [`encode_and_save_frame_to_jpeg_on_viewer_demand.cpp`](/examples/cpp/encode_and_save_frame_to_jpeg_on_viewer_demand.cpp)
+
+```python
+#
+# This example demonstrates the use of a Frame-Capture Sink to encode and
+# save video frames to JPEG files on client/viewer demand.
+#
+# An ODE Frame-Capture Action is provided to The Frame-Capture Sink on creation.
+# A client "capture_complete_listener" is added to the the Action to be notified
+# when each new file is saved (the ODE Action performs the actual frame-capture).
+#
+# Child Players (to play the captured image) and Mailers (to mail the image) can
+# be added to the ODE Frame-Capture action as well (not shown).
+#
+# The "invocation" of a new Frame-Capture is done by pressing the "C" key while
+# the Window Sink has user focus... i.e. the xwindow_key_event_handler will call
+# the "dsl_sink_frame_capture_initiate" service on key-event.
+#
+# IMPORT All captured frames are copied and buffered in the Sink's processing
+# thread. The encoding and saving of each buffered frame is done in the
+# g-idle-thread, therefore, the capture-complete notification is asynchronous.
+#
+```
+
+
+---
+
+### Encode and Save Frames periodically using Multi-Image Sink
+
+* [`encode_and_save_frame_to_jpeg_thumbnail_periodically.py`](/examples/python/encode_and_save_frame_to_jpeg_thumbnail_periodically.py)
+* [`encode_and_save_frame_to_jpeg_thumbnail_periodically.cpp`](/examples/cpp/encode_and_save_frame_to_jpeg_thumbnail_periodically.cpp)
+
+```python
+#
+# This example demonstrates the use of a Multi-Image Sink to encode and
+# save video frames to JPEG files at specified dimensions and frame-rate.
+#
+# The ouput file path/names are specified using a printf style %d in the
+# provided absolute or relative path.
+# eample: "./my_images/image.%d04.jpg", will create files in "./my_images/"
+# named "image.0000.jpg", "image.0001.jpg", "image.0002.jpg" etc.
+#
+# You can limit the number of files that are saved on disc by calling
+# dsl_sink_multi_image_file_max_set. Default = 0 = no max.
+#
+# Once max-files is reached, old files will be deleted to make room for new
+# ones.
+#
+```
+
+
+
diff --git a/docs/examples-ode-services.md b/docs/examples-ode-services.md
new file mode 100644
index 00000000..e52673d2
--- /dev/null
+++ b/docs/examples-ode-services.md
@@ -0,0 +1,522 @@
+# Object Detection Event (ODE) Services
+This page covers examples using [ODE Pad Probe Handlers](/docs/api-pph.md#object-detection-event-ode-pad-probe-handler), [ODE Triggers](/docs/api-ode-trigger.md), [ODE Actions](/docs/api-ode-action.md), [ODE Areas](/docs/api-ode-area.md), [ODE Acummulators](/docs/api-ode-accumulator.md), and [ODE Heat Mappers](/docs/api-ode-heat-mapper.md).
+* [Occurrence Trigger with Monitor Action](#occurrence-trigger-with-monitor-action)
+* [Always Trigger with Display Metadata Action and Source Display Types](#always-trigger-with-display-metadata-action-and-source-display-types)
+* [Minimum, Maximum, Range, and Summation Triggers, with Display Types and Actions](#minimum-maximum-range-and-summation-triggers-with-display-types-and-actions)
+* [Distance Trigger with Format BBox Action](#distance-trigger-with-format-bbox-action)
+* [New Instance Triggers and Print Action](#new-instance-triggers-and-print-action)
+* [Intersection Triggers with Format BBox and Print Actions](#intersection-triggers-with-format-bbox-and-print-actions)
+* [Largest Trigger with Fill Surroundings Action](#largest-trigger-with-fill-surroundings-action)
+* [Cross Trigger with Line Area and ODE Accumulator with Display Action](#cross-trigger-with-line-area-and-ode-accumulator-with-display-action)
+* [New High and New Low Count Triggers with Fill Frame and Print Event Data Actions](#new-high-and-new-low-count-triggers-with-fill-frame-and-print-event-data-actions)
+* [Occurrence Trigger with Area of Inclusion or Exclusion](#occurrence-trigger-with-area-of-inclusion-or-exclusion)
+* [Instance Trigger with Capture Frame Action with a Mailer to Email Frame as Attachement](#instance-trigger-with-capture-frame-action-with-a-mailer-to-email-frame-as-attachement)
+* [Occurrence Trigger with ODE Head Mapper using RGBA Color Palettes](#occurrence-trigger-with-ode-head-mapper-using-rgba-color-palettes)
+* [Persistence Triggers with Format BBox Actions](#persistence-triggers-with-format-bbox-actions)
+* [Persistence and Earliest Triggers with Customize Label and Display Actions](#persistence-and-earliest-triggers-with-customize-label-and-display-actions)
+
+
+
+---
+
+### Occurrence Trigger with Monitor Action
+
+* [`ode_occurrence_trigger_with_monitor_action.py`](/examples/python/ode_occurrence_trigger_with_monitor_action.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates the use of an "ODE Monitor Action" -- added to an
+# ODE Occurrence Trigger with the below criteria -- to monitor all
+# ODE Occurrences
+# - class id = PGIE_CLASS_ID_VEHICLE
+# - inference-done-only = TRUE
+# - minimum confidience = VEHICLE_MIN_CONFIDENCE
+# - minimum width = VEHICLE_MIN_WIDTH
+# - minimum height = VEHICLE_MIN_HEIGHT
+#
+# The ode_occurrence_monitor callback function (defined below) is added to the
+# "Monitor Action" to be called with the ODE Occurrence event data for
+# each detected object that meets the above criteria.
+#
+# The application can process the event data as needed. This examples simply
+# prints all of the event data to console.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - Two Secondary GST Inference Engines (SGIEs)
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+
+---
+
+### Always Trigger with Display Metadata Action and Source Display Types
+
+* [`ode_always_trigger_display_source_info.py`](/examples/python/ode_always_trigger_display_source_info.py)
+* cpp example is still to be done
+
+```python
+#
+# This Example demonstrates how to use an ODE Always Trigger to update the
+# metadata of every frame to display specific information for each Source.
+#
+# 4 Sources are used, each with unique camara names.
+#
+# 3 Display Types are used to create the metadata to be added to each frame:
+# * Source Stream Id
+# * Source Name
+# * Source Dimensions
+#
+# The 3 Display Types are added to an "Add Display Meta Action" which
+# adds the metadata to a given frame.
+#
+# The ODE Action is added to an "Always Trigger" that always triggers once
+# per frame in every batched frame (requires source=DSL_ODE_ANY_SOURCE).
+#
+# The ODE Trigger is added to a "ODE Pad Probe Handler" that is added
+# to the sink (input) pad of the 2D Tiler. The ODE Handler is called with
+# every batched frame that crosses over the Tilers sink pad.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - 4 URI Sources
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - 2D Tiler
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+![](/Images/ode_always_trigger_display_source_info.png)
+
+
+---
+
+### Minimum, Maximum, Range, and Summation Triggers, with Display Types and Actions
+
+* [`ode_always_trigger_display_source_info.py`](/examples/python/ode_always_trigger_display_source_info.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates how to use Minimum, Maximum, and Range Triggers.
+#
+# The triggers, upon meeting all criteria, will add a small rectangle (using
+# a "Display Type" and "Add Display Metadata Action") on the Frame with the
+# following colors indicating:
+# Yellow = object count below Minimum
+# Red = object count above Maximum
+# Green = object count in range of Minimim to Maximum.
+#
+# An additional "Summation Trigger" with a "Display Action" will display the
+# total number of objects next to the colored/filled indicator (rectangle)
+#
+# The ODE Triggers are added to an ODE Pad Probe Handler which is added to
+# source (output) pad of the Tracker.
+
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+![](/Images/ode_count_trigger_display_meta.png)
+
+
+---
+
+### Distance Trigger with Format BBox Action
+
+* [`ode_distance_trigger_fill_object.py`](/examples/python/ode_distance_trigger_fill_object.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates the use of an ODE Distance Trigger to trigger on the
+# occurrence of two objects of different class id that are closer that a
+# minimum distance - specifically testing the distance between People and Vehicles.
+# The bounding boxes for the two objects that are witin the minimim distance will.
+# be filled (using a Format BBox Action) with a color for visual indication of
+# the events.
+
+# The Distance trigger is created with minimim distance critera as a percentage
+# of the width of Class A in the A/B distance measurement. In this example,
+# Class A will be the Person class and Class B the Vehicle class. ODE Occurrence
+# will be triggered if the distance between any Person and Vehicle is measured to
+# be less 250% of the width of the Person's BBox. Maximum is set to 0 == no maximum.
+# Note: Class A and Class B can be set to the same Class Id or DSL_ODE_ANY_CLASS.
+# test_point is DSL_BBOX_POINT_SOUTH == measuring from center points of bottom edges.
+# test_method is DSL_DISTANCE_METHOD_PERCENT_WIDTH_A == % of Person's BBox width.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+![](/Images/ode_distance_trigger_fill_object.png)
+
+
+
+---
+
+### New Instance Triggers and Print Action
+
+* [`ode_instance_trigger_print_action.py`](/examples/python/ode_instance_trigger_print_action.py)
+* cpp example is still to be done
+
+
+```python
+#
+# This example demonstrates the use of two ODE Instance Triggers -- one for
+# the Person class and the other for the Vehicle class -- to trigger on new
+# Object instances as identified by an IOU Tracker. A Print Action is added
+# to the Instance Triggers to print out the event data for each new object.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+
+An example of the Object Dection Event (ODE) data printed to the console by the ODE Print Trigger
+
+```
+Trigger Name : person-instance-trigger
+ Unique ODE Id : 249
+ NTP Timestamp : 2024-09-14 14:13:10.084472
+ Source Data : ------------------------
+ Inference : Yes
+ Source Id : 0x00000000
+ Batch Id : 0
+ Pad Index : 0
+ Frame : 18
+ Width : 1920
+ Heigh : 1080
+ Object Data : ------------------------
+ Obj ClassId : 2
+ Infer Id : 1
+ Tracking Id : 1
+ Label : person
+ Infer Conf : 0.260092
+ Track Conf : 1
+ Persistence : 0
+ Direction : 0
+ Left : 405
+ Top : 464
+ Width : 65
+ Height : 240
+ Criteria : ------------------------
+ Class Id : 2
+ Infer Id : -1
+ Min Infer Conf : 0
+ Min Track Conf : 0
+ Min Frame Count : 1 out of 1
+ Min Width : 0
+ Min Height : 0
+ Max Width : 0
+ Max Height : 0
+ Inference : No
+```
+
+
+---
+
+### Intersection Triggers with Format BBox and Print Actions
+
+* [`ode_intersection_trigger_min_max_dimensions.py`](/examples/python/ode_intersection_trigger_min_max_dimensions.py)
+* cpp example is still to be done
+
+```python
+#
+# This example is used to demonstrate the Use of Two Intersection Triggers,
+# one for the Vehicle class the other for the Person class. A "Format BBox"
+# action will be used to shade the background of the Objects intersecting.
+# Person intersecting with Person and Vehicle intersecting with Vehicle.
+#
+# Min and Max Dimensions will set as addional criteria for the Preson and
+# Vehicle Triggers respecively
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+![](/Images/ode_intersection_trigger_min_max_dimensions.png)
+
+
+
+---
+
+### Largest Trigger with Fill Surroundings Action
+
+* [`ode_largest_object_fill_surroundings.py`](/examples/python/ode_largest_object_fill_surroundings.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates the used of a "Largest Object Trigger" and "Fill
+# Surroundings Action" to continuosly highlight the largest object in the Frame
+# as measured by bounding box area.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+![](/Images/ode_largest_object_fill_surroundings.png)
+
+
+
+
+---
+
+### Cross Trigger with Line Area and ODE Accumulator with Display Action
+
+* [`ode_line_cross_object_capture_overlay_image.py`](/examples/python/ode_line_cross_object_capture_overlay_image.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates the use of an ODE Cross Trigger with an ODE Line Area
+# and ODE Accumulator to accumulate occurrences of an object (person) crossing
+# the line. The Accumulator uses an ODE Display Action to add the current counts
+# of the IN and OUT crossings as display-metadata to each frame.
+#
+# The bounding box and historical trace of each object (tracked by the "Cross
+# Trigger") is assigned a new random RGBA color and added as display-metadata
+# to each frame.
+#
+# An ODE Capture Object Action with an Image Render Player is added to the Cross
+# Trigger to capture and render an image of each object (person) that crosses the
+# line. Each image is displayed for 3 seconds. All files are written to the current
+# directory (configurable).
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A File Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+![](/Images/line-cross-capture-overlay-object-image.png)
+
+
+
+---
+
+### New High and New Low Count Triggers with Fill Frame and Print Event Data Actions
+
+* [`ode_new_high_new_low_triggers_fill_frame.py`](/examples/python/ode_new_high_new_low_triggers_fill_frame.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates the use of the New-High and New-Low Count Triggers
+# that trigger on new high and low object counts respectively. The frame is
+# filled with a full color for a (brief) visual indication on each new occurrence.
+# A print Action is used to print the event data to the console as well.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+
+
+---
+
+### Occurrence Trigger with Area of Inclusion or Exclusion
+
+* [`ode_occurrence_polygon_area_inclussion_exclusion.py`](/examples/python/ode_occurrence_polygon_area_inclussion_exclusion.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates the use of a Polygon Area for Inclusion
+# or Exclusion criteria for ODE occurrence.
+#
+# A "Polygon Display Type" is used to create either an ODE Area of Inclusion or
+# Exclusion based on the AREA_TYPE variable defined below.
+#
+# The ODE Area is then added to an ODE Occurrence Trigger to be used as criteria
+# for ODE occurrence.
+#
+# A "Format BBox Action" is used to fill each detected object that triggers
+# occurrence with an opaque red color for visual confirmation.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+![](/Images/ode_occurrence_polygon_area_inclussion_exclusion.png)
+
+
+
+---
+
+### Instance Trigger with Capture Frame Action with a Mailer to Email Frame as Attachement
+
+* [`ode_instance_frame_capture_email_attachment.py`](/examples/python/ode_instance_frame_capture_email_attachment.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demostrates the use of an "ODE Occurrence Trigger" to trigger
+# on every occurrence of every Person within a Polygon ODE Inclusion Area.
+# The Trigger uses a "Format BBox Action" to fill each occurrence with
+# an opaque red color for visual confirmation while the Person is in the Area.
+#
+# An Instance Trigger is then used to Trigger on every new Instance detected in
+# the same ODE Area.. i.e. when the Person is first detected in the Area and only
+# once.
+# This Trigger uses a "Frame Capture Action" to capture and encode the frame
+# and save it to file. The Action then uses a Mailer component to mail the
+# image as an attachment using DSL's SMTP services.
+#
+# IMPORTANT! it is STRONGLY advised that you create a new, free Gmail account --
+# that is seperate/unlinked from all your other email accounts -- strictly for
+# the purpose of sending ODE Event data uploaded from DSL. Then, add your
+# Personal email address as a "To" address to receive the emails.
+#
+# Gmail considers regular email programs (i.e Outlook, etc.) and non-registered
+# third-party apps to be "less secure". The email account used for sending email
+# must have the "Allow less secure apps" option turned on. Once you've created
+# this new account, you can go to the account settings and enable Less secure
+# app access. see https://myaccount.google.com/lesssecureapps
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+
+
+---
+
+### Occurrence Trigger with ODE Head Mapper using RGBA Color Palettes
+
+* [`ode_occurrence_trigger_with_heat_mapper.py`](/examples/python/ode_occurrence_trigger_with_heat_mapper.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates the use of an ODE Heat-Mapper added to an
+# ODE Occurrence trigger that triggers on every Person occurrence.
+# The occurrence data is mapped/ovelaid on everyframe. The example creates
+# all 5 predefined RGBA Color Palettes - Spectral, Red, Green, Blue, and Grey.
+# The ODE Heat-Mapper is created with the Spectral palette, but can be updated
+# at runtime by pressing the 'N' key.
+#
+# Several keys, bound to the Window Sink, are mapped to the ODE Heat Mapper services
+# - 'N' key maps to 'next' color palette with - dsl_ode_heat_mapper_color_palette_set
+# - 'C' key maps to 'clear' heat-map metrics - dsl_ode_heat_mapper_metrics_clear
+# - 'P' key maps to 'print' heat-map metrics - dsl_ode_heat_mapper_metrics_print
+# - 'L' key maps to 'log' heat-map metrics - dsl_ode_heat_mapper_metrics_log
+# - 'G' key maps to 'get' heat-map metrics - dsl_ode_heat_mapper_metrics_get
+#
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+![](/Images/spectral-person-heat-map.png)
+
+
+
+---
+
+### Persistence Triggers with Format BBox Actions
+
+* [`ode_persistence_trigger_fill_tracked_objects.py`](/examples/python/ode_persistence_trigger_fill_tracked_objects.py)
+* cpp example is still to be done
+
+```python
+#
+# This example demonstrates the use of three ODE Persistence Triggers to trigger on
+# all tracked Objects - as identified by an IOU Tracker - that persist accross consecutive
+# frames for a specifid period of time. Each trigger specifies a range of minimum and
+# maximum times of persistence.
+# Trigger 1: 0 - 3 seconds - action = fill object with opaque green color
+# Trigger 2: 3 - 6 seconds - action = fill object with opaque yellow color
+# Trigger 3: 6 - 0 seconds - action = fill object with opaque red color
+# This will have the effect of coloring an object by its time in view
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+
+
+---
+
+### Persistence and Earliest Triggers with Customize Label and Display Actions
+
+* [`ode_persistence_and_earliest_triggers_custom_labels.py`](/examples/python/ode_persistence_and_earliest_triggers_custom_labels.py)
+* cpp example is still to be done
+
+```python
+#
+# This script demonstrates the use of a Persistence Trigger to trigger on each Vehicle
+# that is tracked for more than one frame -- to calculate the time of Object persistence
+# from the first frame the object was detected.
+#
+# The Tracked Object's label is then "customized" to show the tracking Id and time of
+# persistence for each tracked Vehicle.
+#
+# The script also creates an Earliest Trigger to trigger on the Vehicle that appeared
+# the earliest -- i.e. the object with greatest persistence value -- and displays that
+# Object's persistence using an ODE Display Action.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+```
+![](/Images/display-action-screenshot.png)
diff --git a/docs/examples-opencv.md b/docs/examples-opencv.md
new file mode 100644
index 00000000..10828640
--- /dev/null
+++ b/docs/examples-opencv.md
@@ -0,0 +1,88 @@
+# Dynamic Pipelines
+
+
+* [Working with OpenCV in a Custom Pad Probe Handler - Python](#working-with-opencv-in-a-custom-pad-probe-handler---python)
+* [Working with OpenCV in a Custom Pad Probe Handler - C/C++](#working-with-opencv-in-a-custom-pad-probe-handler---cc)
+---
+
+# Working with OpenCV in a Custom Pad Probe Handler - Python
+
+* [`4file_custom_pph_using_opencv.py`](/examples/python/4file_custom_pph_using_opencv.py)
+
+```python
+#
+# This simple example demonstrates how to use OpenCV with NVIDIA's pyds.
+# The Pipeline used in this example is built with :
+# - 4 URI Sources
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - Tiler
+# - On-Screen Display (OSD)
+# - Window Sink
+#
+# A Custom Pad-Probe-Handler is added to the Sink-Pad of the Tiler
+# to process the frame meta-data for each buffer received. The handler
+# demonstrates how to
+# - use pyds.get_nvds_buf_surface() to get a buffer surface.
+# - convert a frame to numpy array format with np.array().
+# - convert the array into cv2 default BGRA format using cv2.cvtColor().
+# - save the array as an image using opencv cv2.imwrite().
+#
+# IMPORTANT! pyds.get_nvds_buf_surface() requires
+# 1. The color format of the buffer must be set to RGBA by calling
+# dsl_source_video_buffer_out_format_set()
+# 2. The memory type must be set to DSL_NVBUF_MEM_TYPE_CUDA_UNIFIED
+# if running on dGPU. This is done by calling
+# * dsl_pipeline_streammux_nvbuf_mem_type_set() - if using old streammux
+# * dsl_component_nvbuf_mem_type_set_many() - with all sources if using
+# new streammux.
+#
+# IMPORTANT! The output folders (1 per source) must be created first
+# ./stream_0, ./stream_1, ./stream_2, ./stream_3,
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
+
+
+---
+
+# Working with OpenCV in a Custom Pad Probe Handler - C/C++
+
+C/C++
+
+* [`4file_custom_pph_using_opencv.cpp`](/examples/cpp/4file_custom_pph_using_opencv.cpp)
+
+```python
+#
+# This simple example demonstrates how to use OpenCV with the DSL Surface
+# Transform utility classes in /src/"DslSurfaceTransform.h"
+#
+# The Pipeline used in this example is built with :
+# - 4 URI Sources
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - Tiler
+# - On-Screen Display (OSD)
+# - Window Sink
+#
+# A Custom Pad-Probe-Handler is added to the Sink-Pad (input) of the Tiler
+# to process the frame meta-data for each buffer received. The handler
+# demonstrates how to
+# - create an RGBA buffer-surface from a single frame in a batched buffer
+# using the utility classes in /src/"DslSurfaceTransform.h"
+# - convert the buffer serface to a jpeg image using OpenCV.
+#
+# IMPORTANT! All captured images are save to the IMAGE_OUTDIR = "./";
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+```
diff --git a/docs/examples-python.md b/docs/examples-python.md
deleted file mode 100644
index 40d07eba..00000000
--- a/docs/examples-python.md
+++ /dev/null
@@ -1,293 +0,0 @@
-## *Warning: this page is extreamly out of date!*
-
-It is scheduled to be updated to coincide with the firts official Beta comming this fall. Untill then, please refer to the current set of working python examples [available here](/examples/python)
-
-# DSL Python Examples
-Note: Many of the examples use the NVIDIA® DeepStream [Python-bindings](https://github.com/NVIDIA-AI-IOT/deepstream_python_apps#python-bindings) (pyds.so), which can be downloaded from [here](https://developer.nvidia.com/deepstream-download#python_bindings).
-
-**List of Examples:**
-* [1csi_live_pgie_demuxer_osd_overlay_rtsp_h264](#1csi_live_pgie_demuxer_osd_overlay_rtsp_h264)
-* [1csi_live_pgie_ktl_tiller_redaction_osd_window](#1csi_live_pgie_ktl_tiller_redaction_osd_window)
-* [1csi_live_pgie_tiler_osd_window](#1csi_live_pgie_tiler_osd_window)
-* [1rtsp_1csi_live_pgie_tiler_osd_window](#1rtsp_1csi_live_pgie_tiler_osd_window)
-* [1uri_file_dewarper_pgie_ktl_3sgie_tiler_osd_bmh_window](#1uri_file_dewarper_pgie_ktl_3sgie_tiler_osd_bmh_window)
-* [1uri_file_pgie_iou_tiler_osd_bmh_window](#1uri_file_pgie_iou_tiler_osd_bmh_window)
-* [1uri_file_pgie_ktl_tiler_osd_bmh_window](#1uri_file_pgie_ktl_tiler_osd_bmh_window)
-* [1uri_file_pgie_ktl_tiler_osd_window_h264_mkv](#1uri_file_pgie_ktl_tiler_osd_window_h264_mkv)
-* [1uri_file_pgie_ktl_tiler_osd_window_h265_mp4](#1uri_file_pgie_ktl_tiler_osd_window_h265_mp4)
-* [1uri_file_pgie_ktl_tiler_osd_window_image_frame_capture](#1uri_file_pgie_ktl_tiler_osd_window_image_frame_capture)
-* [1uri_file_pgie_ktl_tiler_window_image_object_capture](#1uri_file_pgie_ktl_tiler_window_image_object_capture)
-* [1uri_https_tiler_window_dyn_overlay](#1uri_https_tiler_window_dyn_overlay)
-* [2rtsp_splitter_demuxer_pgie_ktl_tiler_osd_window_2_file](#2rtsp_splitter_demuxer_pgie_ktl_tiler_osd_window_2_file)
-* [2uri_file_pgie_ktl_3sgie_tiler_osd_bmh_window](#2uri_file_pgie_ktl_3sgie_tiler_osd_bmh_window)
-* [4uri_file_pgie_ktl_tiler_osd_overlay](#4uri_file_pgie_ktl_tiler_osd_overlay)
-* [4uri_live_pgie_tiler_osd_window](#4uri_live_pgie_tiler_osd_window)
-* [dyn_uri_file_pgie_ktl_tiler_osd_window](#dyn_uri_file_pgie_ktl_tiler_osd_window)
-
-### 1csi_live_pgie_demuxer_osd_overlay_rtsp_h264
-* 1 Live CSI Camera Source
-* Primary GIE using labels in config file
-* Demuxer - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
- * `nvidia_osd_sink_pad_buffer_probe` batch-meta-handler (bmh) callback added
-* Overlay Sink - render over main display (0)
-* RTSP Sink - H.264 RTSP Server
-
-### 1csi_live_pgie_ktl_tiller_redaction_osd_window
-* 1 Live CSI Camera Source
-* Primary GIE using labels in config file
-* KTL Tracker
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
- * Redaction enabled for ClassId = 0
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
-
-### 1csi_live_pgie_tiler_osd_window
-* 1 Live CSI Camera Source
-* Primary GIE using labels in config file
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
-
-### 1rtsp_1csi_live_pgie_tiler_osd_window
-* 1 Live RTSP Camera Source
-* 1 Live CSI Camera Source
-* Primary GIE using labels in config file
-* Tiler
-* On-Screen-Display
- * Clock enabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
-
-### 1uri_file_dewarper_pgie_ktl_3sgie_tiler_osd_bmh_window
-* 1 URI File Source - playback of 360 degree camera source
-* Dewarper using provided config file
-* Primary GIE using labels in config file
-* KTL Tracker
-* 3 Secondary GIEs - all set to infer on the Primary GIE
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
- * `nvidia_osd_sink_pad_buffer_probe` batch-meta-handler (bmh) callback added
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 1uri_file_pgie_iou_tiler_osd_bmh_window
-* 1 H.264 URI File Source
-* Primary GIE using labels in config file
-* IOU Tracker using provided config file
-* 3 Secondary GIEs - all set to infer on the Primary GIE
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
- * `nvidia_osd_sink_pad_buffer_probe` batch-meta-handler (bmh) callback added
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 1uri_file_pgie_ktl_tiler_osd_bmh_window
-* 1 H.264 URI File Source
-* Primary GIE using labels in config file
-* KTL Tracker
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
- * `nvidia_osd_sink_pad_buffer_probe` batch-meta-handler (bmh) callback added
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 1uri_file_pgie_ktl_tiler_osd_window_h264_mkv
-* 1 H.264 URI File Source
-* Primary GIE using labels in config file
-* KTL Tracker
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* File Sink
- * H.264 encoder
- * MKV media container
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 1uri_file_pgie_ktl_tiler_osd_window_h265_mp4
-* 1 H.265 URI File Source
-* Primary GIE using labels in config file
-* KTL Tracker
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* File Sink
- * H.265 encoder
- * MP4 media container
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 1uri_file_pgie_ktl_tiler_osd_window_image_frame_capture
-* 1 H.265 URI File Source
-* Primary GIE using labels in config file
-* KTL Tracker
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* Image Sink
- * Outdir for jpeg image files set to current directory`./`
- * Frame Capture enabled with an interval of every 60th frame
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 1uri_file_pgie_ktl_tiler_window_image_object_capture
-* 1 H.265 URI File Source
-* Primary GIE using labels in config file
-* KTL Tracker
-* Tiler - demuxer or tiler is required, even with one source
-* On-Screen-Display
- * Clock enabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* Image Sink
- * Outdir for jpeg image files set to current directory`./`
- * Object Capture enabled for PERSON and VEHICLE classes, both with a capture limit of 50 images.
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 1uri_https_tiler_window_dyn_overlay
-* 1 https URI source ('https://www.radiantmediaplayer.com/media/bbb-360p.mp4')
-* Tiler - demuxer or tiler is required, even with one source
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* Dynamic Add/Remove Overlay Sinks
- * Using `xwindow_key_event_handler`
- * Press `'+'` to add a new Overlay Sink - main display
- * Press `'-'` to remove last added
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 2rtsp_splitter_demuxer_pgie_ktl_tiler_osd_window_2_file
-* 2 Live RTSP Camera Source
-* 1 Splitter with two branches to split the stream after the Stream Muxer
- * Branch 1.
- * 1 Demuxer to demux the batch stream back to 2 streams
- * 2 H.264 URI File Sink, one for each stream
- * Branch 2.
- * Primary GIE using labels in config file
- * KTL Tracker
- * Tiler
- * On-Screen-Display
- * Clock enabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
-
-### 2uri_file_pgie_ktl_3sgie_tiler_osd_bmh_window
-* 1 H.264 URI File Source
-* 1 H.265 URI File Source
-* Primary GIE using labels in config file
-* KTL Tracker
-* 3 Secondary GIEs - all set to infer on the Primary GIE
-* Tiler
-* On-Screen-Display
- * Clock enabled
- * Default colors
- * `nvidia_osd_sink_pad_buffer_probe` batch-meta-handler (bmh) callback added
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
- * `state_change_listener` added to Pipeline
-
-### 2uri_file_pgie_ktl_demuxer_1osd_1overlay_1window
-* 1st H.264 URI File Source
- * Overlay Sink - downstream of demuxer
-* 2nd H.264 URI File Source
- * On-Screen-Display - downstream of demuxer
- * Default X11 Window Sink - downstream of demuxer
- * `xwindow_delete_event_handler` added to Pipeline
-* Primary GIE using labels in config file
-* KTL Tracker
-* Demuxer
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
-
-### 4uri_file_pgie_ktl_tiler_osd_overlay
-* 4 H.264 URI File Sources
-* Primary GIE using labels in config file
-* KTL Tracker
-* Tiler
-* On-Screen-Display
- * Clock disabled
- * Default colors
-* Overlay sink - main window
-* Other Callbacks
- * `eos_event_listener` added to Pipeline
-
-### 4uri_live_pgie_tiler_osd_window
-* 4 http URI Live Sources - CalTrans traffic cammeras - low resolution
-* Primary GIE using labels in config file
-* Tiler
-* On-Screen-Display
- * Clock disabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
-
-### dyn_uri_file_pgie_ktl_tiler_osd_window
-* Dynamic Add/Remove URI File Sources - initially 1
- * Using `xwindow_key_event_handler`
- * Press `'+'` to add a new URI FIle Source
- * Press `'-'` to remove last added
-* Primary GIE using labels in config file
-* Tiler
-* On-Screen-Display
- * Clock disabled
- * Default colors
-* Default X11 Window Sink
- * `xwindow_delete_event_handler` added to Pipeline
- * `xwindow_key_event_handler` added to Pipeline
-
-
diff --git a/docs/examples-smart-recording.md b/docs/examples-smart-recording.md
new file mode 100644
index 00000000..e7b4cd1b
--- /dev/null
+++ b/docs/examples-smart-recording.md
@@ -0,0 +1,189 @@
+# Smart Recording Taps and Sinks
+This page documents the following "Smart Recording" examples:
+* [Start Smart Recording Tap on Object Detection Event Occurrence](#start-smart-recording-tap-on-object-detection-event-occurrence)
+* [Start Smart Recording Tap on User or Application Demand](#start-smart-recording-tap-on-user-or-application-demand)
+* [Start Smart Recording Sink on Object Detection Event Occurrence](#start-smart-recording-sink-on-object-detection-event-occurrence)
+* [Start Smart Recording Sink On User or Application Demand](#start-smart-recording-sink-on-user-or-application-demand)
+
+
+
+---
+
+### Start Smart Recording Tap on Object Detection Event Occurrence
+
+* [`smart_record_tap_start_session_on_ode_occurrence.py`](/examples/python/smart_record_tap_start_session_on_ode_occurrence.py)
+* [`smart_record_tap_start_session_on_ode_occurrence.cpp`](/examples/cpp/smart_record_tap_start_session_on_ode_occurrence.cpp)
+
+```python
+# ````````````````````````````````````````````````````````````````````````````````````
+# This example demonstrates the use of a Smart-Record Tap and how to start
+# a recording session on the "occurrence" of an Object Detection Event (ODE).
+# An ODE Occurrence Trigger, with a limit of 1 event, is used to trigger
+# on the first detection of a Person object. The Trigger uses an ODE "Start
+# Recording Session Action" setup with the following parameters:
+# start: the seconds before the current time (i.e.the amount of
+# cache/history to include.
+# duration: the seconds after the current time (i.e. the amount of
+# time to record after session start is called).
+# Therefore, a total of start-time + duration seconds of data will be recorded.
+#
+# **IMPORTANT!**
+# 1. The default max_size for all Smart Recordings is set to 600 seconds. The
+# recording will be truncated if start + duration > max_size.
+# Use dsl_tap_record_max_size_set to update max_size.
+# 2. The default cache-size for all recordings is set to 60 seconds. The
+# recording will be truncated if start > cache_size.
+# Use dsl_tap_record_cache_size_set to update cache_size.
+#
+# Record Tap components tap into RTSP Source components pre-decoder to enable
+# smart-recording of the incomming (original) H.264 or H.265 stream.
+#
+# Additional ODE Actions are added to the Trigger to 1) print the ODE
+# data (source-id, batch-id, object-id, frame-number, object-dimensions, etc.)
+# to the console and 2) to capture the object (bounding-box) to a JPEG file.
+#
+# A basic inference Pipeline is used with PGIE, Tracker, Tiler, OSD, and Window Sink.
+#
+# DSL Display Types are used to overlay text ("REC") with a red circle to
+# indicate when a recording session is in progress. An ODE "Always-Trigger" and an
+# ODE "Add Display Meta Action" are used to add the text's and circle's metadata
+# to each frame while the Trigger is enabled. The record_event_listener callback,
+# called on both DSL_RECORDING_EVENT_START and DSL_RECORDING_EVENT_END, enables
+# and disables the "Always Trigger" according to the event received.
+#
+# IMPORTANT: the record_event_listener is used to reset the one-shot Occurrence-
+# Trigger when called with DSL_RECORDING_EVENT_END. This allows a new recording
+# session to be started on the next occurrence of a Person.
+#
+# IMPORTANT: this demonstrates a multi-source Pipeline, each with their own
+# Smart-Recort Tap.
+
+#!/usr/bin/env python
+```
+
+
+---
+
+### Start Smart Recording Tap on User or Application Demand
+
+* [`smart_record_tap_start_session_on_user_demand.py`](/examples/python/smart_record_tap_start_session_on_user_demand.py)
+* [`smart_record_tap_start_session_on_user_demand.cpp`](/examples/cpp/smart_record_tap_start_session_on_user_demand.cpp)
+
+```python
+# ````````````````````````````````````````````````````````````````````````````````````
+# This example demonstrates the use of a Smart-Record Tap and how
+# to start a recording session on user/viewer demand - in this case
+# by pressing the 'S' key. The xwindow_key_event_handler calls
+# dsl_tap_record_session_start with:
+# start: the seconds before the current time (i.e.the amount of
+# cache/history to include.
+# duration: the seconds after the current time (i.e. the amount of
+# time to record after session start is called).
+# Therefore, a total of start-time + duration seconds of data will be recorded.
+#
+# **IMPORTANT!**
+# 1. The default max_size for all Smart Recordings is set to 600 seconds. The
+# recording will be truncated if start + duration > max_size.
+# Use dsl_tap_record_max_size_set to update max_size.
+# 2. The default cache-size for all recordings is set to 60 seconds. The
+# recording will be truncated if start > cache_size.
+# Use dsl_tap_record_cache_size_set to update cache_size.
+#
+# Record Tap components tap into RTSP Source components pre-decoder to enable
+# smart-recording of the incomming (original) H.264 or H.265 stream.
+#
+# A basic inference Pipeline is used with PGIE, Tracker, OSD, and Window Sink.
+#
+# DSL Display Types are used to overlay text ("REC") with a red circle to
+# indicate when a recording session is in progress. An ODE "Always-Trigger" and an
+# ODE "Add Display Meta Action" are used to add the text's and circle's metadata
+# to each frame while the Trigger is enabled. The record_event_listener callback,
+# called on both DSL_RECORDING_EVENT_START and DSL_RECORDING_EVENT_END, enables
+# and disables the "Always Trigger" according to the event received.
+```
+
+
+---
+
+# Start Smart Recording Sink on Object Detection Event Occurrence
+
+* [`smart_record_sink_start_session_on_ode_occurrence.py`](/examples/python/smart_record_sink_start_session_on_ode_occurrence.py)
+* [`smart_record_sink_start_session_on_ode_occurrence.cpp`](/examples/cpp/smart_record_sink_start_session_on_ode_occurrence.cpp)
+
+```python
+# ````````````````````````````````````````````````````````````````````````````````````
+# This example demonstrates the use of a Smart-Record Sink and how to start
+# a recording session on the "occurrence" of an Object Detection Event (ODE).
+# An ODE Occurrence Trigger, with a limit of 1 event, is used to trigger
+# on the first detection of a Person object. The Trigger uses an ODE "Start
+# Recording Session Action" setup with the following parameters:
+# start: the seconds before the current time (i.e.the amount of
+# cache/history to include.
+# duration: the seconds after the current time (i.e. the amount of
+# time to record after session start is called).
+# Therefore, a total of start-time + duration seconds of data will be recorded.
+#
+# **IMPORTANT!**
+# 1. The default max_size for all Smart Recordings is set to 600 seconds. The
+# recording will be truncated if start + duration > max_size.
+# Use dsl_sink_record_max_size_set to update max_size.
+# 2. The default cache-size for all recordings is set to 60 seconds. The
+# recording will be truncated if start > cache_size.
+# Use dsl_sink_record_cache_size_set to update cache_size.
+#
+# Additional ODE Actions are added to the Trigger to 1) to print the ODE
+# data (source-id, batch-id, object-id, frame-number, object-dimensions, etc.)
+# to the console and 2) to capture the object (bounding-box) to a JPEG file.
+#
+# A basic inference Pipeline is used with PGIE, Tracker, OSD, and Window Sink.
+#
+# DSL Display Types are used to overlay text ("REC") with a red circle to
+# indicate when a recording session is in progress. An ODE "Always-Trigger" and an
+# ODE "Add Display Meta Action" are used to add the text's and circle's metadata
+# to each frame while the Trigger is enabled. The record_event_listener callback,
+# called on both DSL_RECORDING_EVENT_START and DSL_RECORDING_EVENT_END, enables
+# and disables the "Always Trigger" according to the event received.
+#
+# IMPORTANT: the record_event_listener is used to reset the one-shot Occurrence-
+# Trigger when called with DSL_RECORDING_EVENT_END. This allows a new recording
+# session to be started on the next occurrence of a Person.
+```
+
+
+---
+
+### Start Smart Recording Sink On User or Application Demand
+
+* [`smart_record_sink_start_session_on_user_demand.py`](/examples/python/smart_record_sink_start_session_on_user_demand.py)
+* [`smart_record_sink_start_session_on_user_demand.cpp`](/examples/cpp/smart_record_sink_start_session_on_user_demand.cpp)
+
+```python
+# ````````````````````````````````````````````````````````````````````````````````````
+# This example demonstrates the use of a Smart-Record Sink and how
+# to start a recording session on user/viewer demand - in this case
+# by pressing the 'S' key. The xwindow_key_event_handler calls
+# dsl_sink_record_session_start with:
+# start: the seconds before the current time (i.e.the amount of
+# cache/history to include.
+# duration: the seconds after the current time (i.e. the amount of
+# time to record after session start is called).
+# Therefore, a total of start-time + duration seconds of data will be recorded.
+#
+# **IMPORTANT!**
+# 1. The default max_size for all Smart Recordings is set to 600 seconds. The
+# recording will be truncated if start + duration > max_size.
+# Use dsl_sink_record_max_size_set to update max_size.
+# 2. The default cache-size for all recordings is set to 60 seconds. The
+# recording will be truncated if start > cache_size.
+# Use dsl_sink_record_cache_size_set to update cache_size.
+#
+# A basic inference Pipeline is used with PGIE, Tracker, OSD, and Window Sink.
+#
+# DSL Display Types are used to overlay text ("REC") with a red circle to
+# indicate when a recording session is in progress. An ODE "Always-Trigger" and an
+# ODE "Add Display Meta Action" are used to add the text's and circle's metadata
+# to each frame while the Trigger is enabled. The record_event_listener callback,
+# called on both DSL_RECORDING_EVENT_START and DSL_RECORDING_EVENT_END, enables
+# and disables the "Always Trigger" according to the event received.
+```
+
diff --git a/docs/examples-sources-tiler-demuxer.md b/docs/examples-sources-tiler-demuxer.md
new file mode 100644
index 00000000..db131af5
--- /dev/null
+++ b/docs/examples-sources-tiler-demuxer.md
@@ -0,0 +1,97 @@
+# Pipelines with multiple Sources and Tiler or Demuxer
+Examples using
+* [4 HTTP URI Sources, PGIE, Tracker, 2D Tiler, OSD, and Window Sink](#4-http-uri-sources-pgie-tracker-2d-tiler-osd-and-window-sink)
+* [4 URI Sources with 2D Tiler Show Source Control](#4-uri-sources-with-2d-tiler-show-source-control)
+* [2 URI Sources with Demuxer and 2 Branches](#2-uri-sources-with-demuxer-and-2-branches)
+
+**Note:** there are other Tiler and Demuxer examples documented under
+* [Advanced Inference Pipelies](/docs/examples-advanced-pipelines.md)
+* [Dynamic Pipelines](/docs/examples-dynamic-pipelines.md)
+* [Working with OpenCV](/docs/examples-opencv.md)
+* [Diagnostics and Utilites](/docs/examples-diagnaostics-and-utilities.md)
+
+
+
+---
+
+### 4 HTTP URI Sources, PGIE, Tracker, 2D Tiler, OSD, and Window Sink
+
+* [`4http_pgie_iou_tracker_tiler_osd_window.py`](/examples/python/4http_pgie_iou_tracker_tiler_osd_window.py)
+* [`4http_pgie_iou_tracker_tiler_osd_window.cpp`](/examples/cpp/4http_pgie_iou_tracker_tiler_osd_window.cpp)
+
+```python
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - 4 HTTP URI Sources
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - 2D Tiler
+# - On-Screen Display
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - source-buffering messages
+# - key-release events
+# - delete-window events
+#
+# When using non-live streaming sources -- like the HTTP URI in this example --
+# the application should pause the Pipeline when ever a Source is buffering. The
+# buffering_message_handler() callback funtion is added to the Pipeline to
+# be called when a buffering-message is recieved on the Pipeline bus.
+# The callback input parameters are
+# - source - Source of the message == -uridecodebin
+# - percent - the current buffer size as a percentage of the high watermark.
+# - client_data - unused in this simple example
+# When a buffering message is received (percent < 100) the calback will pause
+# the Pipeline. When a buffering message with 100% is received the callback
+# resumes the Pipeline playback,
+#
+```
+
+
+
+---
+
+### 4 URI Sources with 2D Tiler Show Source Control
+
+* [`4uri_file_tiler_show_source_control.py`](/examples/python/4uri_file_tiler_show_source_control.py)
+* [`4uri_file_tiler_show_source_control.cpp`](/examples/cpp/4uri_file_tiler_show_source_control.cpp)
+
+```python
+#
+# This example demonstrates how to manually control -- using key release and
+# button press events -- the 2D Tiler's output stream to:
+# - show a specific source on key input (source No.) or mouse click on tile.
+# - to return to showing all sources on 'A' key input, mouse click, or timeout.
+# - to cycle through all sources on 'C' input showing each for timeout.
+#
+# Note: timeout is controled with the global variable SHOW_SOURCE_TIMEOUT
+#
+# The example uses a basic inference Pipeline consisting of:
+# - 4 URI Sources
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - 2D Tiler
+# - On-Screen Display
+# - Window Sink
+#
+```
+
+
+
+---
+
+### 2 URI Sources with Demuxer and 2 Branches
+
+* [`2uri_file_pgie_iou_tracker_demuxer_2osd_2window.py`](/examples/python/2uri_file_pgie_iou_tracker_demuxer_2osd_2window.py)
+* [`2uri_file_pgie_iou_tracker_demuxer_2osd_2window.cpp`](/examples/cpp/2uri_file_pgie_iou_tracker_demuxer_2osd_2window.cpp)
+
+```python
+#
+# This example demonstrates how to create an Inference Pipeline with two
+# Sources, built-in Streammuxer, and Demuxer with two branches; one per demuxed
+# Stream. Eaxh branch has an On-Screen-Display and EGL Window Sink.
+#
+```
\ No newline at end of file
diff --git a/docs/overview.md b/docs/overview.md
index e107c691..f830c659 100644
--- a/docs/overview.md
+++ b/docs/overview.md
@@ -126,7 +126,7 @@ There are nine primary classes of [Components](/docs/api-component.md) that can
## Sources
[Sources](/docs.api-source.md) are the head components for all DSL [Pipelines](/docs/api-pipeline.md) and [Players](docs/api-player.md). Pipelines must have at least one Source (and one [Sink](/docs/api-sink.md)) to transition to a state of `PLAYING`. All Pipelines have the ability to multiplex multiple source streams -- using their own built-in Stream Muxer -- as long as all Sources are of the same play-type; live vs. non-live.
-There are eleven (12) types of Source components supported, all are currently Video only. Audio-Video and Audio only Sources are currently in development.
+There are twelve (12) types of Source components supported, all are currently Video only. Audio-Video and Audio only Sources are currently in development.
* [App Source](/docs/api-source.md#dsl_source_app_new) - Allows the application to insert raw samples or buffers into a DSL Pipeline.
* [CSI Source](/docs/api-source.md#dsl_source_csi_new) - Camera Serial Interface (CSI) Source - Jetson platform only.
* [V4L2 Source](/docs/api-source.md#dsl_source_v4l2_new) - Stream from any V4L2 compatable device - a USB Webcam for example.
diff --git a/examples/cpp/1file_pgie_iou_tracker_osd_window_file.cpp b/examples/cpp/1file_pgie_iou_tracker_osd_window_file.cpp
index 7d3160fa..7184d3c4 100644
--- a/examples/cpp/1file_pgie_iou_tracker_osd_window_file.cpp
+++ b/examples/cpp/1file_pgie_iou_tracker_osd_window_file.cpp
@@ -26,7 +26,7 @@ THE SOFTWARE.
#
# This simple example demonstrates how to create a set of Pipeline components,
# specifically:
-# - A File Source
+# - File Source
# - Primary GST Inference Engine (PGIE)
# - IOU Tracker
# - On-Screen Display
@@ -204,6 +204,11 @@ int main(int argc, char** argv)
retval = dsl_pipeline_eos_listener_add(L"pipeline", eos_event_listener, NULL);
if (retval != DSL_RESULT_SUCCESS) break;
+ // Add the State Change listener function defined above
+ retval = dsl_pipeline_state_change_listener_add(L"pipeline",
+ state_change_listener, NULL);
+ if (retval != DSL_RESULT_SUCCESS) break;
+
// Play the pipeline
retval = dsl_pipeline_play(L"pipeline");
if (retval != DSL_RESULT_SUCCESS) break;
@@ -215,7 +220,7 @@ int main(int argc, char** argv)
}
// Print out the final result
- std::cout << dsl_return_value_to_string(retval) << std::endl;
+ std::wcout << dsl_return_value_to_string(retval) << std::endl;
dsl_delete_all();
diff --git a/examples/cpp/1file_pgie_iou_tracker_osd_window_rtsp.cpp b/examples/cpp/1file_pgie_iou_tracker_osd_window_rtsp.cpp
index ea997e0e..46232ad7 100644
--- a/examples/cpp/1file_pgie_iou_tracker_osd_window_rtsp.cpp
+++ b/examples/cpp/1file_pgie_iou_tracker_osd_window_rtsp.cpp
@@ -203,6 +203,11 @@ int main(int argc, char** argv)
retval = dsl_pipeline_eos_listener_add(L"pipeline", eos_event_listener, NULL);
if (retval != DSL_RESULT_SUCCESS) break;
+ // Add the State Change listener function defined above
+ retval = dsl_pipeline_state_change_listener_add(L"pipeline",
+ state_change_listener, NULL);
+ if (retval != DSL_RESULT_SUCCESS) break;
+
// Play the pipeline
retval = dsl_pipeline_play(L"pipeline");
if (retval != DSL_RESULT_SUCCESS) break;
diff --git a/examples/cpp/1file_pgie_iou_tracker_osd_window_v4l2.cpp b/examples/cpp/1file_pgie_iou_tracker_osd_window_v4l2.cpp
index 481ece69..472fc0c1 100644
--- a/examples/cpp/1file_pgie_iou_tracker_osd_window_v4l2.cpp
+++ b/examples/cpp/1file_pgie_iou_tracker_osd_window_v4l2.cpp
@@ -199,6 +199,11 @@ int main(int argc, char** argv)
retval = dsl_pipeline_eos_listener_add(L"pipeline", eos_event_listener, NULL);
if (retval != DSL_RESULT_SUCCESS) break;
+ // Add the State Change listener function defined above
+ retval = dsl_pipeline_state_change_listener_add(L"pipeline",
+ state_change_listener, NULL);
+ if (retval != DSL_RESULT_SUCCESS) break;
+
// Play the pipeline
retval = dsl_pipeline_play(L"pipeline");
if (retval != DSL_RESULT_SUCCESS) break;
diff --git a/examples/cpp/1file_preproc_pgie_iou_osd_window.cpp b/examples/cpp/1file_preproc_pgie_iou_tracker_osd_window.cpp
similarity index 97%
rename from examples/cpp/1file_preproc_pgie_iou_osd_window.cpp
rename to examples/cpp/1file_preproc_pgie_iou_tracker_osd_window.cpp
index 90be67d7..fb0648c1 100644
--- a/examples/cpp/1file_preproc_pgie_iou_osd_window.cpp
+++ b/examples/cpp/1file_preproc_pgie_iou_tracker_osd_window.cpp
@@ -195,6 +195,11 @@ int main(int argc, char** argv)
retval = dsl_pipeline_eos_listener_add(L"pipeline", eos_event_listener, NULL);
if (retval != DSL_RESULT_SUCCESS) break;
+ // Add the State Change listener function defined above
+ retval = dsl_pipeline_state_change_listener_add(L"pipeline",
+ state_change_listener, NULL);
+ if (retval != DSL_RESULT_SUCCESS) break;
+
// Play the pipeline
retval = dsl_pipeline_play(L"pipeline");
if (retval != DSL_RESULT_SUCCESS) break;
diff --git a/examples/cpp/1file_ptis_tracker_osd_window.cpp b/examples/cpp/1file_ptis_iou_tracker_osd_window.cpp
similarity index 100%
rename from examples/cpp/1file_ptis_tracker_osd_window.cpp
rename to examples/cpp/1file_ptis_iou_tracker_osd_window.cpp
diff --git a/examples/cpp/1rtsp_pgie_dcf_tracker_osd_window.cpp b/examples/cpp/1rtsp_pgie_dcf_tracker_osd_window.cpp
new file mode 100644
index 00000000..dcd33c34
--- /dev/null
+++ b/examples/cpp/1rtsp_pgie_dcf_tracker_osd_window.cpp
@@ -0,0 +1,247 @@
+/*
+The MIT License
+
+Copyright (c) 2024, Prominence AI, Inc.
+
+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.
+*/
+
+/*################################################################################
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - RTSP Source
+# - Primary GST Inference Engine (PGIE)
+# - DCF Tracker
+# - On-Screen Display (OSD)
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - error-message events
+# - Pipeline change-of-state events
+# - RTSP Source change-of-state events.
+#
+# IMPORTANT! The error-message-handler callback fucntion will stop the Pipeline
+# and main-loop, and then exit. If the error condition is due to a camera
+# connection failure, the application could choose to let the RTSP Source's
+# connection manager periodically reattempt connection for some length of time.
+#
+##############################################################################*/
+
+#include
+#include
+#include
+#include
+#include
+#include "DslApi.h"
+
+
+// RTSP Source URI for AMCREST Camera
+std::wstring amcrest_rtsp_uri =
+ L"rtsp://username:password@192.168.1.108:554/cam/realmonitor?channel=1&subtype=0";
+
+// RTSP Source URI for HIKVISION Camera
+std::wstring hikvision_rtsp_uri =
+ L"rtsp://username:password@192.168.1.64:554/Streaming/Channels/101";
+
+// Config and model-engine files
+std::wstring primary_infer_config_file(
+ L"/opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-preprocess-test/config_infer.txt");
+std::wstring primary_model_engine_file(
+ L"/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet.etlt_b8_gpu0_int8.engine");
+
+// Config file used by the IOU Tracker
+std::wstring dcf_tracker_config_file(
+ L"/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_tracker_NvDCF_max_perf.yml");
+
+// IMPORTANT! "DCF Tracker width and height paramaters must be multiples of 32
+uint tracker_width = 640;
+uint tracker_height = 384;
+
+// EGL Window Sink Dimensions
+uint WINDOW_WIDTH = DSL_1K_HD_WIDTH / 2;
+uint WINDOW_HEIGHT = DSL_1K_HD_HEIGHT / 2;
+
+//
+// Function to be called on XWindow KeyRelease event
+//
+void xwindow_key_event_handler(const wchar_t* in_key, void* client_data)
+{
+ std::wstring wkey(in_key);
+ std::string key(wkey.begin(), wkey.end());
+ std::cout << "key released = " << key << std::endl;
+
+ key = std::toupper(key[0]);
+ if(key == "P"){
+ dsl_pipeline_pause(L"pipeline");
+ } else if (key == "R"){
+ dsl_pipeline_play(L"pipeline");
+ } else if (key == "Q" or key == "" or key == ""){
+ std::cout << "Main Loop Quit" << std::endl;
+ dsl_pipeline_stop(L"pipeline");
+ dsl_main_loop_quit();
+ }
+}
+
+//
+// Function to be called on XWindow Delete event
+//
+void xwindow_delete_event_handler(void* client_data)
+{
+ std::cout<<"delete window event"<
+#include
+#include
+#include
+#include
+#include "DslApi.h"
+
+// URI for the Source Component
+std::wstring source_uri(
+ L"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4");
+
+// Config and model-engine files
+std::wstring primary_infer_config_file(
+ L"/opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-preprocess-test/config_infer.txt");
+std::wstring primary_model_engine_file(
+ L"/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet.etlt_b8_gpu0_int8.engine");
+
+// Config file used by the IOU Tracker
+std::wstring iou_tracker_config_file(
+ L"/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_tracker_IOU.yml");
+
+// EGL Window Sink Dimensions
+uint WINDOW_WIDTH = DSL_1K_HD_WIDTH / 2;
+uint WINDOW_HEIGHT = DSL_1K_HD_HEIGHT / 2;
+
+boolean buffering = false;
+
+//
+// Function to be called when a buffering-message is recieved on the Pipeline bus.
+//
+void buffering_message_handler(const wchar_t* source, uint percent, void* client_data)
+{
+
+ if (percent == 100)
+ {
+ std::cout << "playing pipeline - buffering complete at 100 %"
+ << std::endl;
+ dsl_pipeline_play(L"pipeline");
+ buffering = false;
+ }
+ else
+ {
+ if (!buffering)
+ {
+ std::cout << "pausing pipeline - buffering starting at "
+ << percent << "%" << std::endl;
+ dsl_pipeline_pause(L"pipeline");
+ }
+ buffering = true;
+ }
+}
+
+//
+// Function to be called on XWindow KeyRelease event
+//
+void xwindow_key_event_handler(const wchar_t* in_key, void* client_data)
+{
+ std::wstring wkey(in_key);
+ std::string key(wkey.begin(), wkey.end());
+ std::cout << "key released = " << key << std::endl;
+
+ key = std::toupper(key[0]);
+ if(key == "P"){
+ dsl_pipeline_pause(L"pipeline");
+ } else if (key == "R"){
+ dsl_pipeline_play(L"pipeline");
+ } else if (key == "Q" or key == "" or key == ""){
+ std::cout << "Main Loop Quit" << std::endl;
+ dsl_pipeline_stop(L"pipeline");
+ dsl_main_loop_quit();
+ }
+}
+
+//
+// Function to be called on XWindow Delete event
+//
+void xwindow_delete_event_handler(void* client_data)
+{
+ std::cout<<"delete window event"<
#include
@@ -291,7 +302,7 @@ int main(int argc, char** argv)
}
// Print out the final result
- std::cout << dsl_return_value_to_string(retval) << std::endl;
+ std::wcout << dsl_return_value_to_string(retval) << std::endl;
dsl_delete_all();
diff --git a/examples/cpp/parallel_inference_on_selective_streams.cpp b/examples/cpp/parallel_inference_on_selective_streams.cpp
index 07fc2dd1..2edee1c8 100644
--- a/examples/cpp/parallel_inference_on_selective_streams.cpp
+++ b/examples/cpp/parallel_inference_on_selective_streams.cpp
@@ -43,7 +43,7 @@ THE SOFTWARE.
#
# dsl_remuxer_branch_add(L"remuxer", 'my-branch-0')
#
-# In this example, 4 sources are added to the Pipeline:
+# In this example, 4 RTSP Sources are added to the Pipeline:
# - branch-1 will process streams [0,1]
# - branch-2 will process streams [1,2]
# - branch-3 will process streams [0,2,3]
@@ -67,15 +67,14 @@ THE SOFTWARE.
#include
#include "DslApi.h"
-// File path for the single File Source
-std::wstring file_path1(
- L"/opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h265.mp4");
-std::wstring file_path2(
- L"/opt/nvidia/deepstream/deepstream/samples/streams/sample_qHD.mp4");
-std::wstring file_path3(
- L"/opt/nvidia/deepstream/deepstream/samples/streams/sample_ride_bike.mov");
-std::wstring file_path4(
- L"/opt/nvidia/deepstream/deepstream/samples/streams/sample_walk.mov");
+
+// RTSP Source URI for AMCREST Camera
+std::wstring amcrest_rtsp_uri =
+ L"rtsp://username:password@192.168.1.108:554/cam/realmonitor?channel=1&subtype=0";
+
+// RTSP Source URI for HIKVISION Camera
+std::wstring hikvision_rtsp_uri =
+ L"rtsp://admin:Segvisual44@192.168.1.64:554/Streaming/Channels/101";
// All branches are currently using the same config and model engine files
// which is pointless... The example will be updated to use multiple
@@ -164,14 +163,18 @@ int main(int argc, char** argv)
// # Since we're not using args, we can Let DSL initialize GST on first call
while(true)
{
- // 4new File Sources to produce streams 0 through 3
- retval = dsl_source_file_new(L"source-1", file_path1.c_str(), true);
+ // 4 new RTSP Sources to produce streams 0 through 3
+ retval = dsl_source_rtsp_new(L"rtsp-source-0",
+ hikvision_rtsp_uri.c_str(), DSL_RTP_ALL, 0, 0, 1000, 10);
if (retval != DSL_RESULT_SUCCESS) break;
- retval = dsl_source_file_new(L"source-2", file_path2.c_str(), true);
+ retval = dsl_source_rtsp_new(L"rtsp-source-1",
+ hikvision_rtsp_uri.c_str(), DSL_RTP_ALL, 0, 0, 1000, 10);
if (retval != DSL_RESULT_SUCCESS) break;
- retval = dsl_source_file_new(L"source-3", file_path3.c_str(), true);
+ retval = dsl_source_rtsp_new(L"rtsp-source-2",
+ hikvision_rtsp_uri.c_str(), DSL_RTP_ALL, 0, 0, 1000, 10);
if (retval != DSL_RESULT_SUCCESS) break;
- retval = dsl_source_file_new(L"source-4", file_path4.c_str(), true);
+ retval = dsl_source_rtsp_new(L"rtsp-source-3",
+ hikvision_rtsp_uri.c_str(), DSL_RTP_ALL, 0, 0, 1000, 10);
if (retval != DSL_RESULT_SUCCESS) break;
// ----------------------------------------------------------------------------
@@ -343,7 +346,8 @@ int main(int argc, char** argv)
// ----------------------------------------------------------------------------
// Create a list of Pipeline Components to add to the new Pipeline.
- const wchar_t* components[] = {L"source-1", L"source-2", L"source-3", L"source-4",
+ const wchar_t* components[] = {
+ L"rtsp-source-0", L"rtsp-source-1", L"rtsp-source-2", L"rtsp-source-3",
L"remuxer", L"tiler", L"osd", L"window-sink", NULL};
// Add all the components to our pipeline
diff --git a/examples/cpp/raw_i420_app_src_ptis_tracker_osd_window.cpp b/examples/cpp/raw_i420_app_src_ptis_tracker_osd_window.cpp
index cc2a9069..38cffceb 100644
--- a/examples/cpp/raw_i420_app_src_ptis_tracker_osd_window.cpp
+++ b/examples/cpp/raw_i420_app_src_ptis_tracker_osd_window.cpp
@@ -24,22 +24,24 @@ THE SOFTWARE.
*/
/*
-This example illustrates how to push raw video buffers to a DSL Pipeline
-using an App Source component. The example application adds the following
-client handlers to control the input of raw buffers to the App Source
- * need_data_handler - called when the App Source needs data to process
- * enough_data_handler - called when the App Source has enough data to process
-
-The client handlers add/remove a callback function to read, map, and push data
-to the App Source called "read_and_push_data".
-
-The raw video file used with this example is created by executing the following
-gst-launch-1.0 command.
-
-gst-launch-1.0 uridecodebin \
- uri=file:///opt/nvidia/deepstream/deepstream/samples/streams/sample_720p.mp4 \
- ! nvvideoconvert ! 'video/x-raw, format=I420, width=1280, height=720' \
- ! filesink location=./sample_720p.i420
+#
+# This example illustrates how to push raw video buffers to a DSL Pipeline
+# using an App Source component. The example application adds the following
+# client handlers to control the input of raw buffers to the App Source
+# * need_data_handler - called when the App Source needs data to process
+# * enough_data_handler - called when the App Source has enough data to process
+#
+# The client handlers add/remove a callback function to read, map, and push data
+# to the App Source called "read_and_push_data".
+#
+# The raw video file used with this example is created by executing the following
+# gst-launch-1.0 command.
+#
+# gst-launch-1.0 uridecodebin \
+# uri=file:///opt/nvidia/deepstream/deepstream/samples/streams/sample_720p.mp4 \
+# ! nvvideoconvert ! 'video/x-raw, format=I420, width=1280, height=720' \
+# ! filesink location=./sample_720p.i420
+#
*/
#include
diff --git a/examples/python/1csi_live_pgie_osd_window.py b/examples/python/1csi_live_pgie_osd_window.py
deleted file mode 100644
index 14dffb4b..00000000
--- a/examples/python/1csi_live_pgie_osd_window.py
+++ /dev/null
@@ -1,142 +0,0 @@
-################################################################################
-# The MIT License
-#
-# Copyright (c) 2019-2023, Prominence AI, Inc.
-#
-# 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.
-################################################################################
-
-################################################################################
-#
-# The simple example demonstrates how to create a set of Pipeline components,
-# specifically:
-# - CSI Source
-# - Primary GST Inference Engine (PGIE)
-# - On-Screen Display
-# - Window Sink
-# ...and how to add them to a new Pipeline and play
-#
-# The example registers handler callback functions with the Pipeline for:
-# - key-release events
-# - delete-window events
-#
-# IMPORTANT! this examples uses a CSI Camera Source and 3D Sink - Jetson only!
-#
-################################################################################
-
-#!/usr/bin/env python
-
-import sys
-import time
-from dsl import *
-
-SOURCE_WIDTH = 1920
-SOURCE_HEIGHT = 1080
-
-# Filespecs for the Primary GIE
-primary_infer_config_file = \
- '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_infer_primary.txt'
-primary_model_engine_file = \
- '/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet.etlt_b8_gpu0_int8.engine'
-
-##
-# Function to be called on XWindow KeyRelease event
-##
-def xwindow_key_event_handler(key_string, client_data):
- print('key released = ', key_string)
- if key_string.upper() == 'P':
- dsl_pipeline_pause('pipeline')
- elif key_string.upper() == 'R':
- dsl_pipeline_play('pipeline')
- elif key_string.upper() == 'Q' or key_string == '' or key_string == '':
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-##
-# Function to be called on XWindow Delete event
-##
-def xwindow_delete_event_handler(client_data):
- print('delete window event')
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-def main(args):
-
- # Since we're not using args, we can Let DSL initialize GST on first call
- while True:
-
- # New CSI Live Camera Source
- retval = dsl_source_csi_new('csi-source',
- SOURCE_WIDTH, SOURCE_HEIGHT, 30, 1)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Primary GIE using the filespecs above, with inference interval=0
- retval = dsl_infer_gie_primary_new('primary-gie',
- primary_infer_config_file, primary_model_engine_file, 0)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New OSD with text, clock and bbox display all enabled.
- retval = dsl_osd_new('on-screen-display',
- text_enabled=True, clock_enabled=True,
- bbox_enabled=True, mask_enabled=False)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New 3D Window Sink with 0 x/y offsets, and same dimensions as Camera Source
- retval = dsl_sink_window_3d_new('window-sink', 0, 0,
- SOURCE_WIDTH, SOURCE_HEIGHT)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the XWindow event handler functions defined above
- retval = dsl_sink_window_key_event_handler_add("window-sink",
- xwindow_key_event_handler, None)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_sink_window_delete_event_handler_add("window-sink",
- xwindow_delete_event_handler, None)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add all the components to our pipeline
- retval = dsl_pipeline_new_component_add_many('pipeline',
- ['csi-source', 'primary-gie', 'on-screen-display', 'window-sink', None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Play the pipeline
- retval = dsl_pipeline_play('pipeline')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- dsl_main_loop_run()
- retval = DSL_RETURN_SUCCESS
- break
-
- # Print out the final result
- print(dsl_return_value_to_string(retval))
-
- dsl_pipeline_delete_all()
- dsl_component_delete_all()
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv))
-
diff --git a/examples/python/1csi_live_pgie_osd_3dsink_rtsp_h254.py b/examples/python/1csi_pgie_osd_3dsink.py
similarity index 84%
rename from examples/python/1csi_live_pgie_osd_3dsink_rtsp_h254.py
rename to examples/python/1csi_pgie_osd_3dsink.py
index 15f8a30c..eb46f977 100644
--- a/examples/python/1csi_live_pgie_osd_3dsink_rtsp_h254.py
+++ b/examples/python/1csi_pgie_osd_3dsink.py
@@ -30,7 +30,6 @@
# - Primary GST Inference Engine (PGIE)
# - On-Screen Display
# - 3D Sink
-# - RTSP Sink
# ...and how to add them to a new Pipeline and play.
#
# IMPORTANT! this examples uses a CSI Camera Source and 3D Sink - Jetson only!
@@ -84,21 +83,10 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # New RTSP Server Sink
- retVal = dsl_sink_rtsp_server_new('rtsp-sink',
- host = "0.0.0.0", # 0.0.0.0 = "this host, this network."
- udp_port = 5400, # UDP port 5400 uses the Datagram Protocol.
- rtsp_port = 8554, #
- encoder = DSL_ENCODER_HW_H265, # High Efficiency Video Coding (HEVC)
- bitrate = 0, # Set to 0 to use plugin default (4000000)
- iframe_interval = 0) # 0 = encode everyframe
- if retVal != DSL_RETURN_SUCCESS:
- print(dsl_return_value_to_string(retVal))
-
# Add all the components to our pipeline
retval = dsl_pipeline_new_component_add_many('pipeline',
['csi-source', 'primary-gie', 'on-screen-display',
- 'window-sink', 'rtsp-sink', None])
+ 'window-sink', None])
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/1file_pgie_iou_tracker_osd_window_file.py b/examples/python/1file_pgie_iou_tracker_osd_window_file.py
index caf99997..0f3a5374 100644
--- a/examples/python/1file_pgie_iou_tracker_osd_window_file.py
+++ b/examples/python/1file_pgie_iou_tracker_osd_window_file.py
@@ -26,7 +26,7 @@
#
# The simple example demonstrates how to create a set of Pipeline components,
# specifically:
-# - URI Source
+# - File Source
# - Primary GST Inference Engine (PGIE)
# - IOU Tracker
# - On-Screen Display (OSD)
diff --git a/examples/python/1rtsp_pgie_dcf_tracker_osd_window.py b/examples/python/1rtsp_pgie_dcf_tracker_osd_window.py
new file mode 100644
index 00000000..a27e4fad
--- /dev/null
+++ b/examples/python/1rtsp_pgie_dcf_tracker_osd_window.py
@@ -0,0 +1,228 @@
+
+################################################################################
+# The MIT License
+#
+# Copyright (c) 2019-2023, Prominence AI, Inc.
+#
+# 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.
+################################################################################
+
+################################################################################
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - RTSP Source
+# - Primary GST Inference Engine (PGIE)
+# - DCF Tracker
+# - On-Screen Display (OSD)
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - error-message events
+# - Pipeline change-of-state events
+# - RTSP Source change-of-state events.
+#
+# IMPORTANT! The error-message-handler callback fucntion will stop the Pipeline
+# and main-loop, and then exit. If the error condition is due to a camera
+# connection failure, the application could choose to let the RTSP Source's
+# connection manager periodically reattempt connection for some length of time.
+#
+################################################################################
+
+#!/usr/bin/env python
+
+import sys
+import time
+
+from dsl import *
+
+# RTSP Source URI for AMCREST Camera
+amcrest_rtsp_uri = 'rtsp://username:password@192.168.1.108:554/cam/realmonitor?channel=1&subtype=0'
+
+# RTSP Source URI for HIKVISION Camera
+hikvision_rtsp_uri = 'rtsp://username:password@192.168.1.64:554/Streaming/Channels/101'
+
+# Filespecs (Jetson and dGPU) for the Primary GIE
+primary_infer_config_file = \
+ '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_infer_primary.txt'
+primary_model_engine_file = \
+ '/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet.etlt_b8_gpu0_int8.engine'
+
+# Filespec for the NvDCF Tracker config file
+dcf_tracker_config_file = \
+ '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_tracker_NvDCF_max_perf.yml'
+
+# IMPORTANT! "DCF Tracker width and height paramaters must be multiples of 32
+tracker_width = 640
+tracker_height = 384
+
+##
+# Function to be called on XWindow KeyRelease event
+##
+def xwindow_key_event_handler(key_string, client_data):
+ print('key released = ', key_string)
+ if key_string.upper() == 'P':
+ dsl_pipeline_pause('pipeline')
+ elif key_string.upper() == 'R':
+ dsl_pipeline_play('pipeline')
+ elif key_string.upper() == 'Q' or key_string == '' or key_string == '':
+ dsl_pipeline_stop('pipeline')
+ dsl_main_loop_quit()
+
+##
+# Function to be called on XWindow Delete event
+##
+def xwindow_delete_event_handler(client_data):
+ print('delete window event')
+ dsl_pipeline_stop('pipeline')
+ dsl_main_loop_quit()
+
+##
+# Function to be called on End-of-Stream (EOS) event
+##
+def eos_event_listener(client_data):
+ print('Pipeline EOS event')
+ dsl_pipeline_stop('pipeline')
+ dsl_main_loop_quit()
+
+##
+# Function to be called with every error message received
+# by the Pipeline bus manager
+##
+def error_message_handler(source, message, client_data):
+ print('Error: source = ', source, ' message = ', message)
+ dsl_pipeline_stop('pipeline')
+ dsl_main_loop_quit()
+
+##
+# Function to be called on every change of Pipeline state
+##
+def pipeline_state_change_listener(old_state, new_state, client_data):
+ print('previous state = ', old_state, ', new state = ', new_state)
+ if new_state == DSL_STATE_PLAYING:
+ dsl_pipeline_dump_to_dot('pipeline', "state-playing")
+
+##
+# Function to be called on every change of RTSP Source state
+##
+def rtsp_state_change_listener(old_state, new_state, client_data):
+ print('RTSP Source previous state = ',
+ old_state, ', new state = ', new_state)
+
+def main(args):
+
+ # Since we're not using args, we can Let DSL initialize GST on first call
+ while True:
+
+ # New RTSP Source for the specific RTSP URI with a timeout of 10s
+ # IMPORTANT! a timeout > 0 enables the source's connection management.
+ retval = dsl_source_rtsp_new('rtsp-source',
+ uri = hikvision_rtsp_uri, # using hikvision URI defined above
+ protocol = DSL_RTP_ALL, # use RTP ALL protocol
+ skip_frames = 0, # decode every frame
+ drop_frame_interval = 0, # decode every frame
+ latency=1000, # 1000 ms of jitter buffer
+ timeout=10) # 10 second new buffer timeout
+ if (retval != DSL_RETURN_SUCCESS):
+ return retval
+
+ # Add the RTSP state-change listener calback to our RTSP Source
+ retval = dsl_source_rtsp_state_change_listener_add('rtsp-source',
+ rtsp_state_change_listener, None)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # New Primary GIE using the filespecs above with interval = 0
+ retval = dsl_infer_gie_primary_new('primary-gie',
+ primary_infer_config_file, primary_model_engine_file, 0)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # New NvDCF Tracker, setting operation width and height
+ retval = dsl_tracker_new('dcf-tracker',
+ config_file = dcf_tracker_config_file,
+ width = tracker_width,
+ height = tracker_height)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # New OSD with text, clock and bbox display all enabled.
+ retval = dsl_osd_new('on-screen-display', text_enabled=True,
+ clock_enabled=True, bbox_enabled=True, mask_enabled=False)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # New Window Sink, 0 x/y offsets with reduced dimensions
+ retval = dsl_sink_window_egl_new('egl-sink', 0, 0, 1280, 720)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # Add the XWindow event handler functions defined above
+ retval = dsl_sink_window_key_event_handler_add('egl-sink',
+ xwindow_key_event_handler, None)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+ retval = dsl_sink_window_delete_event_handler_add('egl-sink',
+ xwindow_delete_event_handler, None)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # Add all the components to a new pipeline
+ retval = dsl_pipeline_new_component_add_many('pipeline',
+ ['rtsp-source', 'primary-gie', 'dcf-tracker', 'on-screen-display',
+ 'egl-sink', None])
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # Add the error-message handler defined above
+ retval = dsl_pipeline_error_message_handler_add('pipeline',
+ error_message_handler, None)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # Add the listener callback functions defined above
+ retval = dsl_pipeline_state_change_listener_add('pipeline',
+ pipeline_state_change_listener, None)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+ retval = dsl_pipeline_eos_listener_add('pipeline', eos_event_listener, None)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # Play the pipeline
+ retval = dsl_pipeline_play('pipeline')
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
+ # Join with main loop until released - blocking call
+ dsl_main_loop_run()
+ retval = DSL_RETURN_SUCCESS
+ break
+
+ # Print out the final result
+ print(dsl_return_value_to_string(retval))
+
+ dsl_delete_all()
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
\ No newline at end of file
diff --git a/examples/python/2uri_file_pgie_iou_tracker_demuxer_osd_3d_window.py b/examples/python/1uri_http_pgie_iou_tracker_osd_window.py
similarity index 58%
rename from examples/python/2uri_file_pgie_iou_tracker_demuxer_osd_3d_window.py
rename to examples/python/1uri_http_pgie_iou_tracker_osd_window.py
index e7a77021..2b580ed7 100644
--- a/examples/python/2uri_file_pgie_iou_tracker_demuxer_osd_3d_window.py
+++ b/examples/python/1uri_http_pgie_iou_tracker_osd_window.py
@@ -1,3 +1,4 @@
+
################################################################################
# The MIT License
#
@@ -22,6 +23,35 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - HTTP URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display (OSD)
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - component-buffering messages
+# - key-release events
+# - delete-window events
+# - end-of-stream EOS events
+# - Pipeline change-of-state events
+#
+# IMPORTANT! The URI Source will send messages on the Pipeline bus when
+# buffering is in progress. The buffering_message_handler callback is
+# added to the Pipeline to be called with every buffer message received.
+# The handler callback is required to pause the Pipeline while buffering
+# is in progress.
+#
+# The callback is called with the percentage of buffering done, with
+# 100% indicating that buffering is complete.
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -29,9 +59,9 @@
from dsl import *
-uri_h265 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h265.mp4"
+source_uri = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4'
-# Filespecs for the Primary GIE
+# Filespecs (Jetson and dGPU) for the Primary GIE
primary_infer_config_file = \
'/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_infer_primary.txt'
primary_model_engine_file = \
@@ -41,6 +71,26 @@
iou_tracker_config_file = \
'/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_tracker_IOU.yml'
+buffering = False
+
+##
+# Function to be called when a buffering-message is recieved on the Pipeline bus.
+##
+def buffering_message_handler(source, percent, client_data):
+
+ global buffering
+
+ if percent == 100:
+ print('playing pipeline - buffering complete at 100 %')
+ dsl_pipeline_play('pipeline')
+ buffering = False
+
+ else:
+ if not buffering:
+ print('pausing pipeline - buffering starting at ', percent, '%')
+ dsl_pipeline_pause('pipeline')
+ buffering = True
+
##
# Function to be called on XWindow KeyRelease event
##
@@ -62,29 +112,32 @@ def xwindow_delete_event_handler(client_data):
dsl_pipeline_stop('pipeline')
dsl_main_loop_quit()
-##
# Function to be called on End-of-Stream (EOS) event
-##
def eos_event_listener(client_data):
print('Pipeline EOS event')
dsl_pipeline_stop('pipeline')
dsl_main_loop_quit()
+##
+# Function to be called on every change of Pipeline state
+##
+def state_change_listener(old_state, new_state, client_data):
+ print('previous state = ', old_state, ', new state = ', new_state)
+ if new_state == DSL_STATE_PLAYING:
+ dsl_pipeline_dump_to_dot('pipeline', "state-playing")
+
def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
-
- # Two URI File Sources - using the same file.
- retval = dsl_source_uri_new('uri-source-1', uri_h265, False, False, 0)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_source_uri_new('uri-source-2', uri_h265, False, False, 0)
+
+ ## New URI Source with HTTP URI
+ retval = dsl_source_uri_new('uri-source', source_uri, False, False, 0)
if retval != DSL_RETURN_SUCCESS:
break
- # New Primary GIE using the filespecs above, with infer interval
- retval = dsl_infer_gie_primary_new('primary-gie',
+ # New Primary GIE using the filespecs above with interval = 0
+ retval = dsl_infer_gie_primary_new('primary-gie',
primary_infer_config_file, primary_model_engine_file, 0)
if retval != DSL_RETURN_SUCCESS:
break
@@ -94,19 +147,14 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # New 3D Sink with x/y offsets and Dimensions
- retval = dsl_sink_window_3d_new('3d-sink', 100, 100, 360, 180)
- if retval != DSL_RETURN_SUCCESS:
- break
-
# New OSD with text, clock and bbox display all enabled.
- retval = dsl_osd_new('on-screen-display',
- text_enabled=True, clock_enabled=True, bbox_enabled=True, mask_enabled=False)
+ retval = dsl_osd_new('on-screen-display', text_enabled=True,
+ clock_enabled=True, bbox_enabled=True, mask_enabled=False)
if retval != DSL_RETURN_SUCCESS:
break
- # New Window Sink, with x/y offsets and dimensions
- retval = dsl_sink_window_egl_new('egl-sink', 0, 0, 720, 360)
+ # New Window Sink, 0 x/y offsets with reduced dimensions
+ retval = dsl_sink_window_egl_new('egl-sink', 0, 0, 1280, 720)
if retval != DSL_RETURN_SUCCESS:
break
@@ -120,34 +168,34 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # New Branch for the PGIE, OSD and Window Sink
- retval = dsl_branch_new_component_add_many('branch1',
- ['on-screen-display', 'egl-sink', None])
+ # Add all the components to a new pipeline
+ retval = dsl_pipeline_new_component_add_many('pipeline',
+ ['uri-source', 'primary-gie', 'iou-tracker', 'on-screen-display',
+ 'egl-sink', None])
if retval != DSL_RETURN_SUCCESS:
break
- # Add Branch1 and the overlay-sink as Branch2
- retVal = dsl_tee_demuxer_new_branch_add_many('demuxer',
- max_branches=2, branches=['branch1', '3d-sink', None])
+ ## Add the buffering-handler defined above to the pipeline
+ retval = dsl_pipeline_buffering_message_handler_add('pipeline',
+ buffering_message_handler, None)
if retval != DSL_RETURN_SUCCESS:
break
- # Add the sources the components to our pipeline
- retval = dsl_pipeline_new_component_add_many('pipeline',
- ['uri-source-1', 'uri-source-2', 'primary-gie', 'iou-tracker', 'demuxer', None])
+ # Add the listener callback functions defined above
+ retval = dsl_pipeline_state_change_listener_add('pipeline',
+ state_change_listener, None)
if retval != DSL_RETURN_SUCCESS:
break
-
- # Add the window delete handler and EOS listener callbacks to the Pipeline
retval = dsl_pipeline_eos_listener_add('pipeline', eos_event_listener, None)
if retval != DSL_RETURN_SUCCESS:
break
-
+
# Play the pipeline
retval = dsl_pipeline_play('pipeline')
if retval != DSL_RETURN_SUCCESS:
break
+ # Join with main loop until released - blocking call
dsl_main_loop_run()
retval = DSL_RETURN_SUCCESS
break
@@ -158,4 +206,4 @@ def main(args):
dsl_delete_all()
if __name__ == '__main__':
- sys.exit(main(sys.argv))
+ sys.exit(main(sys.argv))
\ No newline at end of file
diff --git a/examples/python/1uri_https_window_dynamic_3d.py b/examples/python/1uri_http_window_dynamic_3d.py
similarity index 100%
rename from examples/python/1uri_https_window_dynamic_3d.py
rename to examples/python/1uri_http_window_dynamic_3d.py
diff --git a/examples/python/2uri_file_demuxer_pgie_iou_tiler_osd_window_2_file.py b/examples/python/2uri_file_demuxer_pgie_iou_tiler_osd_window_2_file.py
deleted file mode 100644
index 0c52716c..00000000
--- a/examples/python/2uri_file_demuxer_pgie_iou_tiler_osd_window_2_file.py
+++ /dev/null
@@ -1,197 +0,0 @@
-################################################################################
-# The MIT License
-#
-# Copyright (c) 2019-2023, Prominence AI, Inc.
-#
-# 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.
-################################################################################
-
-#!/usr/bin/env python
-
-import sys
-import time
-
-from dsl import *
-
-# Filespecs for the Primary GIE
-primary_infer_config_file = \
- '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_infer_primary.txt'
-primary_model_engine_file = \
- '/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet.etlt_b8_gpu0_int8.engine'
-
-# Filespec for the IOU Tracker config file
-iou_tracker_config_file = \
- '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_tracker_IOU.yml'
-
-uri_h265 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h265.mp4"
-
-##
-# Function to be called on XWindow KeyRelease event
-##
-def xwindow_key_event_handler(key_string, client_data):
- print('key released = ', key_string)
- if key_string.upper() == 'P':
- dsl_pipeline_pause('pipeline')
- elif key_string.upper() == 'R':
- dsl_pipeline_play('pipeline')
- elif key_string.upper() == 'Q' or key_string == '' or key_string == '':
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-##
-# Function to be called on XWindow Delete event
-##
-def xwindow_delete_event_handler(client_data):
- print('delete window event')
- dsl_main_loop_quit()
-
-##
-# Function to be called on End-of-Stream (EOS) event
-##
-def eos_event_listener(client_data):
- print('Pipeline EOS event')
- dsl_main_loop_quit()
-
-def main(args):
-
- # Since we're not using args, we can Let DSL initialize GST on first call
- while True:
-
- # Two URI File Sources - using the same file.
- retval = dsl_source_uri_new('source-1', uri_h265, False, 0, 0)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_source_uri_new('source-2', uri_h265, False, 0, 0)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- ## Two new File Sinks with H264 Encoder type and MKV conatiner muxer,
- ## set bit-rate=0 to use default and drop-frame-interval=0
- retval = dsl_sink_file_new('file-sink-1',
- "./1-source.mkv", DSL_ENCODER_HW_H264, DSL_CONTAINER_MKV, 0, 30)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- ## Two new File Sinks with H264 Encoder type and MKV conatiner muxer,
- ## set bit-rate=0 to use default and drop-frame-interval=0
- retval = dsl_sink_file_new('file-sink-2',
- "./2-source.mkv", DSL_ENCODER_HW_H264, DSL_CONTAINER_MKV, 0, 30)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Primary GIE using the filespecs above, with infer interval
- retval = dsl_infer_gie_primary_new('primary-gie',
- primary_infer_config_file, primary_model_engine_file, 5)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New IOU Tracker, setting operational width and hieght
- retval = dsl_tracker_new('iou-tracker', iou_tracker_config_file, 480, 272)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Tiler with dimensions for two tiles - for the two sources
- retval = dsl_tiler_new('tiler1', 1440, 360)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New OSD with text, clock and bbox display all enabled.
- retval = dsl_osd_new('on-screen-display',
- text_enabled=True, clock_enabled=True, bbox_enabled=True, mask_enabled=False)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Window Sink, with matching dimensions as the Tiler
- retval = dsl_sink_window_egl_new('egl-sink', 0, 0, 1440, 360)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the XWindow event handler functions defined above
- retval = dsl_sink_window_key_event_handler_add('egl-sink',
- xwindow_key_event_handler, None)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_sink_window_delete_event_handler_add('egl-sink',
- xwindow_delete_event_handler, None)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Branch for the PGIE, OSD and Window Sink
- retval = dsl_branch_new('branch1')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- retval = dsl_branch_component_add_many('branch1', ['primary-gie', 'iou-tracker', 'tiler1',
- 'on-screen-display', 'egl-sink', None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Demuxer Tee-
- retval = dsl_tee_demuxer_new('demuxer', 2)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the two file sinks as branches to the demuxer
- retval = dsl_tee_branch_add_many('demuxer', ['file-sink-1', 'file-sink-2', None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Splitter Tee-
- retval = dsl_tee_splitter_new('splitter')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add Branch1 and the demuxer (as branch2) to the splitter
- retval = dsl_tee_branch_add_many('splitter', ['branch1', 'demuxer', None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Pipeline to use with the above components
- retval = dsl_pipeline_new('pipeline')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the window delete handler and EOS listener callbacks to the Pipeline
- retval = dsl_pipeline_eos_listener_add('pipeline', eos_event_listener, None)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the sources the components to our pipeline
- retval = dsl_pipeline_component_add_many('pipeline',
- ['source-1', 'source-2', 'splitter', None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Play the pipeline
- retval = dsl_pipeline_play('pipeline')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- dsl_main_loop_run()
- retval = DSL_RETURN_SUCCESS
- break
-
- # Print out the final result
- print(dsl_return_value_to_string(retval))
-
- dsl_pipeline_delete_all()
- dsl_component_delete_all()
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv))
diff --git a/examples/python/2uri_file_pgie_iou_tracker_demuxer_2osd_2window.py b/examples/python/2uri_file_pgie_iou_tracker_demuxer_2osd_2window.py
index 3c748cf1..5c8efaff 100644
--- a/examples/python/2uri_file_pgie_iou_tracker_demuxer_2osd_2window.py
+++ b/examples/python/2uri_file_pgie_iou_tracker_demuxer_2osd_2window.py
@@ -22,6 +22,13 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates how to create an Inference Pipeline with two
+# Sources, built-in Streammuxer, and Demuxer with two branches; one per demuxed
+# Stream. Eaxh branch has an On-Screen-Display and EGL Window Sink.
+#
+################################################################################
#!/usr/bin/env python
import sys
diff --git a/examples/python/4http_pgie_iou_tracker_tiler_osd_window.py b/examples/python/4http_pgie_iou_tracker_tiler_osd_window.py
index 3096594c..56075896 100644
--- a/examples/python/4http_pgie_iou_tracker_tiler_osd_window.py
+++ b/examples/python/4http_pgie_iou_tracker_tiler_osd_window.py
@@ -26,7 +26,7 @@
#
# The simple example demonstrates how to create a set of Pipeline components,
# specifically:
-# - Four HTTP URI Sources
+# - 4 HTTP URI Sources
# - Primary GST Inference Engine (PGIE)
# - IOU Tracker
# - 2D Tiler
diff --git a/examples/python/4uri_file_tiler_show_source_control.py b/examples/python/4uri_file_tiler_show_source_control.py
index 369d4b8f..3b2e9d5a 100644
--- a/examples/python/4uri_file_tiler_show_source_control.py
+++ b/examples/python/4uri_file_tiler_show_source_control.py
@@ -25,6 +25,7 @@
#!/usr/bin/env python
################################################################################
+#
# This example demonstrates how to manually control -- using key release and
# button press events -- the 2D Tiler's output stream to:
# - show a specific source on key input (source No.) or mouse click on tile.
@@ -32,6 +33,15 @@
# - to cycle through all sources on 'C' input showing each for timeout.
#
# Note: timeout is controled with the global variable SHOW_SOURCE_TIMEOUT
+#
+# The example uses a basic inference Pipeline consisting of:
+# - 4 URI Sources
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - 2D Tiler
+# - On-Screen Display
+# - Window Sink
+#
################################################################################
import sys
diff --git a/examples/python/8uri_file_pph_meter_performace_reporting.py b/examples/python/8uri_file_pph_meter_performace_reporting.py
index 68cb44c5..c6a1691f 100644
--- a/examples/python/8uri_file_pph_meter_performace_reporting.py
+++ b/examples/python/8uri_file_pph_meter_performace_reporting.py
@@ -22,6 +22,35 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demostrates how to use a Source Meter Pad Probe Handler (PPH)
+# that will measure the Pipeline's throughput for each Source - while monitoring
+# the depth of every component's Queue.
+#
+# The Meter PPH is added to the sink (input) pad of the Tiler before tha batched
+# stream is converted into a single stream as a 2D composite of all Sources.
+#
+# The "meter_pph_handler" callback added to the Meter PPH will handle writing
+# the Avg Session FPS and the Avg Interval FPS measurements to the console.
+# #
+# The Key-released-handler callback (below) will disable the meter when pausing
+# the Pipeline, and # re-enable measurements when the Pipeline is resumed.
+#
+# Note: Session averages are reset each time the Meter is disabled and
+# then re-enabled.
+#
+# The callback, called once per second as defined during Meter construction,
+# is also responsible for polling the components for their queue depths - i.e
+# using the "dsl_component_queue_current_level_print_many" service.
+#
+# Additionally, a Queue Overrun Listener is added to each of the components to
+# be notified on the event of a queue-overrun.
+#
+# https://github.com/prominenceai/deepstream-services-library/blob/master/docs/api-component.md#component-queue-management
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -167,17 +196,10 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- #
- # New Meter Pad Probe Handler that will measure the Pipeline's throughput.
- # Our client callback will handle writing the Avg Session FPS and the
- # Avg Interval FPS measurements to the console. The Key-released-handler
- # callback (above) will disable the meter when pausing the Pipeline, and
- # re-enable measurements when the Pipeline is resumed
- # Note: Session averages are reset each time the Meter is disabled and
- # then re-enabled.
-
report_data = ReportData()
+ # New Source Meter Pad Probe handler to call the meter_pph_handler with an
+ # interval of 1 second.
retval = dsl_pph_meter_new('meter-pph', interval=1,
client_handler=meter_pph_handler, client_data=report_data)
if retval != DSL_RETURN_SUCCESS:
diff --git a/examples/python/encode_and_save_frame_to_jpeg_from_custom_pph.py b/examples/python/encode_and_save_frame_to_jpeg_from_custom_pph.py
index 379ddd74..33b12b07 100644
--- a/examples/python/encode_and_save_frame_to_jpeg_from_custom_pph.py
+++ b/examples/python/encode_and_save_frame_to_jpeg_from_custom_pph.py
@@ -25,7 +25,7 @@
################################################################################
#
# This example demonstrates the use of a Frame-Capture Sink to encode and
-# save video frames to JPEG files on client/viewer demand.
+# save video frames to JPEG files scheduled from a Custom Pad Probe Handler (PPH).
#
# An ODE Frame-Capture Action is provided to The Frame-Capture Sink on creation.
# A client "capture_complete_listener" is added to the the Action to be notified
diff --git a/examples/python/interpipe_multiple_pipelines_listening_to_single_sink.py b/examples/python/interpipe_multiple_pipelines_listening_to_single_sink.py
index f7406131..f85b6bd3 100644
--- a/examples/python/interpipe_multiple_pipelines_listening_to_single_sink.py
+++ b/examples/python/interpipe_multiple_pipelines_listening_to_single_sink.py
@@ -32,6 +32,7 @@
# The two Pipelines can be created with different configs, models, and/or Trackers
# for side-by-side comparison. Both Pipelines run in their own main-loop with their
# own main-context, and have their own Window Sink for viewing and external control.
+#
#!/usr/bin/env python
diff --git a/examples/python/multiple_pipelines.py b/examples/python/multiple_pipelines.py
index 263239a2..a0d5891e 100644
--- a/examples/python/multiple_pipelines.py
+++ b/examples/python/multiple_pipelines.py
@@ -22,6 +22,17 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates how to run multple Pipelines, each in their own
+# thread, and each with their own main-context and main-loop.
+#
+# After creating and starting each Pipelines, the script joins each of the
+# threads waiting for them to complete - either by EOS message, 'Q' key, or
+# Delete Window.
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -33,14 +44,6 @@
import threading
-#-------------------------------------------------------------------------------------------
-#
-# This script demonstrates the running multple Pipelines, each in their own thread,
-# and each with their own main-context and main-loop.
-#
-# After creating and starting each Pipelines, the script joins each of the threads
-# waiting for them to complete - either by EOS message, 'Q' key, or Delete Window
-
# File path used for all File Sources
file_path = '/opt/nvidia/deepstream/deepstream/samples/streams/sample_qHD.mp4'
diff --git a/examples/python/ode_always_trigger_display_source_info.py b/examples/python/ode_always_trigger_display_source_info.py
index 310c2d18..2756f3b0 100644
--- a/examples/python/ode_always_trigger_display_source_info.py
+++ b/examples/python/ode_always_trigger_display_source_info.py
@@ -22,6 +22,38 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This Example demonstrates how to use an ODE Always Trigger to update the
+# metadata of every frame to display specific information for each Source.
+#
+# 4 Sources are used, each with unique camara names.
+#
+# 3 Display Types are used to create the metadata to be added to each frame:
+# * Source Stream Id
+# * Source Name
+# * Source Dimensions
+#
+# The 3 Display Types are added to an "Add Display Meta Action" which
+# adds the metadata to a given frame.
+#
+# The ODE Action is added to an "Always Trigger" that always triggers once
+# per frame in every batched frame (requires source=DSL_ODE_ANY_SOURCE).
+#
+# The ODE Trigger is added to a "ODE Pad Probe Handler" that is added
+# to the sink (input) pad of the 2D Tiler. The ODE Handler is called with
+# every batched frame that crosses over the Tilers sink pad.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - 4 URI Sources
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - 2D Tiler
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -189,9 +221,9 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # New OSD with text, clock and bbox display all enabled.
+ # New OSD with text and bbox display enabled.
retval = dsl_osd_new('on-screen-display',
- text_enabled=True, clock_enabled=True, bbox_enabled=True, mask_enabled=False)
+ text_enabled=True, clock_enabled=False, bbox_enabled=True, mask_enabled=False)
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/ode_count_trigger_display_meta.py b/examples/python/ode_count_trigger_display_meta.py
index 91dae9a8..d49d055b 100644
--- a/examples/python/ode_count_trigger_display_meta.py
+++ b/examples/python/ode_count_trigger_display_meta.py
@@ -22,6 +22,31 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates how to use Minimum, Maximum, and Range Triggers.
+#
+# The triggers, upon meeting all criteria, will color a small rectangle (using
+# a display type) on the Frame with the following colors indicating:
+# Yellow = object count below Minimum
+# Red = object count above Maximum
+# Green = object count in range of Minimim to Maximum.
+#
+# An additional "Summation Trigger" with a "Display Action" will display the
+# total number of objects next to the colored/filled indicator (rectangle)
+#
+# The ODE Triggers are added to an ODE Pad Probe Handler which is added to
+# source (output) pad of the Tracker.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -96,19 +121,6 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- # This example is used to demonstrate the Use of Minimum, Maximum, and
- # Range Triggers. The triggers, upon meeting all criteria, will fill a
- # rectangle Area on the Frame with color indicating:
- # Yellow = object count below Minimum
- # Red = object count above Maximum
- # Green = object count in range of Minimim to Maximum.
-
- # A secondary indicatory of filling the full Frame with a shade of red
- # will be used to stress that the object count within the frame has
- # exceeded the Maximum
-
- # An additional Summation Trigger with Display Action will display the
- # total number of objects next to the colored/filled area-indicator
#`````````````````````````````````````````````````````````````````````````````
@@ -260,7 +272,7 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # New ODE occurrence Trigger to hide the Display Text for all detected objects
+ # New ODE occurrence Trigger to hide the Label Text for all detected objects
retval = dsl_ode_trigger_occurrence_new('every-object', source=DSL_ODE_ANY_SOURCE,
class_id=DSL_ODE_ANY_CLASS, limit=0)
if retval != DSL_RETURN_SUCCESS:
diff --git a/examples/python/ode_distance_trigger_fill_object.py b/examples/python/ode_distance_trigger_fill_object.py
index c6eee927..df1c6a19 100644
--- a/examples/python/ode_distance_trigger_fill_object.py
+++ b/examples/python/ode_distance_trigger_fill_object.py
@@ -22,6 +22,33 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates the use of an ODE Distance Trigger to trigger on the
+# occurrence of two objects of different class id that are closer that a
+# minimum distance - specifically testing the distance between People and Vehicles.
+# The bounding boxes for the two objects that are witin the minimim distance will.
+# be filled (using a Format BBox Action) with a color for visual indication of
+# the events.
+
+# The Distance trigger is created with minimim distance critera as a percentage
+# of the width of Class A in the A/B distance measurement. In this example,
+# Class A will be the Person class and Class B the Vehicle class. ODE Occurrence
+# will be triggered if the distance between any Person and Vehicle is measured to
+# be less 250% of the width of the Person's BBox. Maximum is set to 0 == no maximum.
+# Note: Class A and Class B can be set to the same Class Id or DSL_ODE_ANY_CLASS.
+# test_point is DSL_BBOX_POINT_SOUTH == measuring from center points of bottom edges.
+# test_method is DSL_DISTANCE_METHOD_PERCENT_WIDTH_A == % of Person's BBox width.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -96,12 +123,6 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- # This example demonstrates the use of an ODE Distance Trigger to trigger on
- # occurrence of two objects of different class id that are closer that a
- # minimum distance - specifically testing the distance between People and Vehicles.
- # The bounding boxes for the two objects that are witin the minimim distance will.
- # be filled with a color for visual indication of the events.
-
#```````````````````````````````````````````````````````````````````````````````````
# Create a Format Label Action to remove the Object Label from view
@@ -161,7 +182,7 @@ def main(args):
# Create the new Distance trigger with minimim distance critera as a percentage
# of the width of Class A in the A/B distance measurement. ODE Occurrence will be
# triggered if the distance between any Person and Vehicle is measured to be less
- # that the 300% of the width of the Person's BBox. Maximum is set to 0 == no maximum
+ # that the 250% of the width of the Person's BBox. Maximum is set to 0 == no maximum
# Note: Class A and Class B can be set to the same Class Id or DSL_ODE_ANY_CLASS.
# test_point is DSL_BBOX_POINT_SOUTH == measuring from center points of bottom edges
# test_method is DSL_DISTANCE_METHOD_PERCENT_WIDTH_A == % of Person's BBox width
@@ -170,7 +191,7 @@ def main(args):
class_id_a = PGIE_CLASS_ID_PERSON,
class_id_b = PGIE_CLASS_ID_VEHICLE,
limit=DSL_ODE_TRIGGER_LIMIT_NONE,
- minimum = 300,
+ minimum = 250,
maximum = 0,
test_point = DSL_BBOX_POINT_SOUTH,
test_method = DSL_DISTANCE_METHOD_PERCENT_WIDTH_A)
@@ -235,22 +256,17 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # New Tiled Display, setting width and height, use default cols/rows set by source count
- retval = dsl_tiler_new('tiler', TILER_WIDTH, TILER_HEIGHT)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add our ODE Pad Probe Handler to the Sink pad of the Tiler
- retval = dsl_tiler_pph_add('tiler', handler='ode-handler', pad=DSL_PAD_SINK)
- if retval != DSL_RETURN_SUCCESS:
- break
-
# New OSD with text, clock and bbox display all enabled.
retval = dsl_osd_new('on-screen-display',
text_enabled=True, clock_enabled=True, bbox_enabled=True, mask_enabled=False)
if retval != DSL_RETURN_SUCCESS:
break
+ # Add our ODE Pad Probe Handler to the Sink pad of the OSD
+ retval = dsl_osd_pph_add('on-screen-display', handler='ode-handler', pad=DSL_PAD_SINK)
+ if retval != DSL_RETURN_SUCCESS:
+ break
+
# New Window Sink, 0 x/y offsets and same dimensions as Tiled Display
retval = dsl_sink_window_egl_new('egl-sink', 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)
if retval != DSL_RETURN_SUCCESS:
@@ -268,7 +284,7 @@ def main(args):
# Add all the components to our pipeline
retval = dsl_pipeline_new_component_add_many('pipeline',
- ['uri-source-1', 'primary-gie', 'iou-tracker', 'tiler',
+ ['uri-source-1', 'primary-gie', 'iou-tracker',
'on-screen-display', 'egl-sink', None])
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/ode_occurrence_frame_capture_email_attachment.py b/examples/python/ode_instance_frame_capture_email_attachment.py
similarity index 89%
rename from examples/python/ode_occurrence_frame_capture_email_attachment.py
rename to examples/python/ode_instance_frame_capture_email_attachment.py
index e1274961..16a1ab02 100644
--- a/examples/python/ode_occurrence_frame_capture_email_attachment.py
+++ b/examples/python/ode_instance_frame_capture_email_attachment.py
@@ -27,7 +27,20 @@
import sys
from dsl import *
-##########################################################################33####
+################################################################################
+#
+# This example demostrates the use of an "ODE Occurrence Trigger" to trigger
+# on every occurrence of every Person within a Polygon ODE Inclusion Area.
+# The Trigger uses a "Format BBox Action" to fill each occurrence with
+# an opaque red color for visual confirmation while the Person is in the Area.
+#
+# An Instance Trigger is then used to Trigger on every new Instance detected in
+# the same ODE Area.. i.e. when the Person is first detected in the Area and only
+# once.
+# This Trigger uses a "Frame Capture Action" to capture and encode the frame
+# and save it to file. The Action then uses a Mailer component to mail the
+# image as an attachment using DSL's SMTP services.
+#
# IMPORTANT! it is STRONGLY advised that you create a new, free Gmail account --
# that is seperate/unlinked from all your other email accounts -- strictly for
# the purpose of sending ODE Event data uploaded from DSL. Then, add your
@@ -39,9 +52,15 @@
# this new account, you can go to the account settings and enable Less secure
# app access. see https://myaccount.google.com/lesssecureapps
#
-# CAUTION - Do not check sripts into your repo with valid credentials
-#
-#######################################################################
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
user_name = 'my.smtps.server'
password = 'my-server-pw'
server_url = 'smtps://smtp.gmail.com:465'
@@ -159,17 +178,15 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- # This example demonstrates the use of a Polygon Area for Inclusion
- # or Exlucion critera for ODE occurrence. Change the variable below to try each.
-
- #```````````````````````````````````````````````````````````````````````````````````
+
+ #````````````````````````````````````````````````````````````````````````````
# Setup the SMTP Server URL, Credentials, and From/To addresss
retval = setup_smpt_mail()
if retval != DSL_RETURN_SUCCESS:
break
- #```````````````````````````````````````````````````````````````````````````````````
+ #````````````````````````````````````````````````````````````````````````````
# Create a Format Label Action to remove the Object Label from view
# Note: the label can be disabled with the OSD API as well.
@@ -184,8 +201,10 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # Create an Any-Class Occurrence Trigger for our remove label and bbox border actions
- retval = dsl_ode_trigger_occurrence_new('every-occurrence-trigger', source='uri-source',
+ # Create an Any-Class Occurrence Trigger for our remove label and bbox border
+ # actions
+ retval = dsl_ode_trigger_occurrence_new('every-occurrence-trigger',
+ source='uri-source',
class_id=DSL_ODE_ANY_CLASS, limit=DSL_ODE_TRIGGER_LIMIT_NONE)
if retval != DSL_RETURN_SUCCESS:
break
@@ -215,7 +234,8 @@ def main(args):
# Create the Polygon display type
retval = dsl_display_type_rgba_polygon_new('polygon1',
- coordinates=coordinates, num_coordinates=len(coordinates), border_width=4, color='opaque-red')
+ coordinates=coordinates, num_coordinates=len(coordinates),
+ border_width=4, color='opaque-red')
if retval != DSL_RETURN_SUCCESS:
break
@@ -234,17 +254,20 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_ode_trigger_area_add('person-in-area-trigger', area='polygon-area')
+ retval = dsl_ode_trigger_area_add('person-in-area-trigger',
+ area='polygon-area')
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_ode_trigger_action_add('person-in-area-trigger', action='fill-action')
+ retval = dsl_ode_trigger_action_add('person-in-area-trigger',
+ action='fill-action')
if retval != DSL_RETURN_SUCCESS:
break
- # New Occurrence Trigger, filtering on PERSON class_id, for our capture object action
- # with a limit of one which will be reset in the capture-complete callback
+ # New Occurrence Trigger, filtering on PERSON class_id, for our capture
+ # object action with a limit of one which will be reset in the
+ # capture-complete callback
retval = dsl_ode_trigger_instance_new('person-enter-area-trigger',
source = DSL_ODE_ANY_SOURCE,
class_id = PGIE_CLASS_ID_PERSON,
@@ -253,11 +276,13 @@ def main(args):
break
# Using the same Inclusion area as the New Occurrence Trigger
- retval = dsl_ode_trigger_area_add('person-enter-area-trigger', area='polygon-area')
+ retval = dsl_ode_trigger_area_add('person-enter-area-trigger',
+ area='polygon-area')
if retval != DSL_RETURN_SUCCESS:
break
- # Create a new Capture Action to capture the Frame to jpeg image, and save to file.
+ # Create a new Capture Action to capture the Frame to jpeg image, and save
+ # to file.
retval = dsl_ode_action_capture_frame_new('person-capture-action',
outdir = "./")
if retval != DSL_RETURN_SUCCESS:
@@ -266,7 +291,8 @@ def main(args):
### ADD THE MAILER OBJECT TO THE CAPTURE FRAME ACTION ###
# The mailer will be used to email information on the Captured Frame
- # -- file location, size, etc. -- with the image file included as an attachment.
+ # -- file location, size, etc. -- with the image file included as an
+ # attachment.
retval = dsl_ode_action_capture_mailer_add('person-capture-action',
mailer = 'mailer',
subject = 'ATTENTION: Person in Area!',
@@ -282,7 +308,7 @@ def main(args):
break
- #```````````````````````````````````````````````````````````````````````````````````````````````````````````````
+ #````````````````````````````````````````````````````````````````````````````
# New ODE Handler to handle all ODE Triggers with their Areas and Actions
retval = dsl_pph_ode_new('ode-handler')
@@ -296,7 +322,7 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- ############################################################################################
+ #############################################################################
#
# Create the remaining Pipeline components
@@ -323,12 +349,14 @@ def main(args):
# New OSD with text, clock and bbox display all enabled.
retval = dsl_osd_new('on-screen-display',
- text_enabled=True, clock_enabled=True, bbox_enabled=True, mask_enabled=False)
+ text_enabled=True, clock_enabled=True,
+ bbox_enabled=True, mask_enabled=False)
if retval != DSL_RETURN_SUCCESS:
break
# Add our ODE Pad Probe Handler to the Sink pad of the Tiler
- retval = dsl_osd_pph_add('on-screen-display', handler='ode-handler', pad=DSL_PAD_SINK)
+ retval = dsl_osd_pph_add('on-screen-display',
+ handler='ode-handler', pad=DSL_PAD_SINK)
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/ode_instance_trigger_message_server.py b/examples/python/ode_instance_trigger_message_server.py
index 29dc949f..546bbe52 100644
--- a/examples/python/ode_instance_trigger_message_server.py
+++ b/examples/python/ode_instance_trigger_message_server.py
@@ -111,11 +111,13 @@ def main(args):
#```````````````````````````````````````````````````````````````````````````````````
# Create two new RGBA fill colors to fill the bounding boxes of new objects
- retval = dsl_display_type_rgba_color_custom_new('solid-red', red=1.0, green=0.0, blue=0.0, alpha=1.0)
+ retval = dsl_display_type_rgba_color_custom_new('solid-red',
+ red=1.0, green=0.0, blue=0.0, alpha=1.0)
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_display_type_rgba_color_custom_new('solid-white', red=1.0, green=1.0, blue=1.0, alpha=1.0)
+ retval = dsl_display_type_rgba_color_custom_new('solid-white',
+ red=1.0, green=1.0, blue=1.0, alpha=1.0)
if retval != DSL_RETURN_SUCCESS:
break
@@ -137,34 +139,39 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # Create a single action to print the event data to the console, which will be used
- # by both our PERSON and VEHICLE Instance Trigers - created next
+ # Create a single action to print the event data to the console, which will
+ # be used by both our PERSON and VEHICLE Instance Trigers - created next
retval = dsl_ode_action_print_new('print-data', force_flush=False)
if retval != DSL_RETURN_SUCCESS:
break
- # Create a single action to add message meta to the frame meta, which will be used
- # by both our PERSON and VEHICLE Instance Trigers - created next. The message meta
- # will be converted to an IoT message payload and sent to Azure server by the
- # downstream message sink.
+ # Create a single action to add message meta to the frame meta, which will
+ # be used by both our PERSON and VEHICLE Instance Trigers - created next.
+ # The message meta will be converted to an IoT message payload and sent to
+ # Azure server by the spacedownstream message sink.
retval = dsl_ode_action_message_meta_add_new('add-message-meta')
if retval != DSL_RETURN_SUCCESS:
break
- #```````````````````````````````````````````````````````````````````````````````````
- # Create two new Instance triggers, one for the PERSON class, the other for the VEHICLE class.
- retval = dsl_ode_trigger_instance_new('person-instance-trigger', source='uri-source-1',
- class_id=PGIE_CLASS_ID_PERSON, limit=DSL_ODE_TRIGGER_LIMIT_NONE)
+ #````````````````````````````````````````````````````````````````````````````
+ # Create two new Instance triggers, one for the PERSON class, the other
+ # for the VEHICLE class.
+ retval = dsl_ode_trigger_instance_new('person-instance-trigger',
+ source='uri-source-1',
+ class_id=PGIE_CLASS_ID_PERSON,
+ limit=DSL_ODE_TRIGGER_LIMIT_NONE)
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_ode_trigger_instance_new('vehicle-instance-trigger', source='uri-source-1',
- class_id=PGIE_CLASS_ID_VEHICLE, limit=DSL_ODE_TRIGGER_LIMIT_NONE)
+ retval = dsl_ode_trigger_instance_new('vehicle-instance-trigger',
+ source='uri-source-1',
+ class_id=PGIE_CLASS_ID_VEHICLE,
+ limit=DSL_ODE_TRIGGER_LIMIT_NONE)
if retval != DSL_RETURN_SUCCESS:
break
- #```````````````````````````````````````````````````````````````````````````````````
+ #````````````````````````````````````````````````````````````````````````````
# Next, we add our Actions to our Triggers
retval = dsl_ode_trigger_action_add_many('person-instance-trigger',
actions=['fill-person-action', 'print-data', 'add-message-meta', None])
@@ -175,7 +182,7 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- #```````````````````````````````````````````````````````````````````````````````````
+ #````````````````````````````````````````````````````````````````````````````
# New ODE Handler to handle all ODE Triggers
retval = dsl_pph_ode_new('ode-handler')
if retval != DSL_RETURN_SUCCESS:
@@ -185,7 +192,7 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- ####################################################################################
+ #############################################################################
#
# Create the remaining Pipeline components
@@ -213,12 +220,14 @@ def main(args):
# New OSD with text, clock and bbox display all enabled.
retval = dsl_osd_new('on-screen-display',
- text_enabled=True, clock_enabled=True, bbox_enabled=True, mask_enabled=False)
+ text_enabled=True, clock_enabled=True,
+ bbox_enabled=True, mask_enabled=False)
if retval != DSL_RETURN_SUCCESS:
break
# New Window Sink, 0 x/y offsets and same dimensions as Tiled Display
- retval = dsl_sink_window_egl_new('egl-sink', 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)
+ retval = dsl_sink_window_egl_new('egl-sink', 0, 0,
+ WINDOW_WIDTH, WINDOW_HEIGHT)
if retval != DSL_RETURN_SUCCESS:
break
@@ -233,20 +242,20 @@ def main(args):
break
# New Message Sink Creation using the filespec defined at the top of the file
- retval = dsl_sink_message_new('message-sink',
- converter_config_file = converter_config_file,
- payload_type = DSL_MSG_PAYLOAD_DEEPSTREAM,
- broker_config_file = broker_config_file,
- protocol_lib = protocol_lib,
- connection_string = connection_string,
- topic = '/instances/')
+ # retval = dsl_sink_message_new('message-sink',
+ # converter_config_file = converter_config_file,
+ # payload_type = DSL_MSG_PAYLOAD_DEEPSTREAM,
+ # broker_config_file = broker_config_file,
+ # protocol_lib = protocol_lib,
+ # connection_string = connection_string,
+ # topic = '/instances/')
if retval != DSL_RETURN_SUCCESS:
break
# Add all the components to our pipeline
retval = dsl_pipeline_new_component_add_many('pipeline',
['uri-source-1', 'primary-gie', 'iou-tracker',
- 'on-screen-display', 'egl-sink', 'message-sink', None])
+ 'on-screen-display', 'egl-sink', None])
if retval != DSL_RETURN_SUCCESS:
break
@@ -255,7 +264,8 @@ def main(args):
state_change_listener, None)
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_pipeline_eos_listener_add('pipeline', eos_event_listener, None)
+ retval = dsl_pipeline_eos_listener_add('pipeline',
+ eos_event_listener, None)
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/ode_instance_trigger_fill_new_object.py b/examples/python/ode_instance_trigger_print_action.py
similarity index 84%
rename from examples/python/ode_instance_trigger_fill_new_object.py
rename to examples/python/ode_instance_trigger_print_action.py
index ea8a149e..de2741ac 100644
--- a/examples/python/ode_instance_trigger_fill_new_object.py
+++ b/examples/python/ode_instance_trigger_print_action.py
@@ -22,6 +22,22 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates the use of two ODE Instance Triggers -- one for
+# the Person class and the other for the Vehicle class -- to trigger on new
+# Object instances as identified by an IOU Tracker. A Print Action is added
+# to the Instance Triggers to print out the event data for each new object.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -91,12 +107,7 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
-
- # This example demonstrates the use of ODE Instance Triggers to trigger on
- # new Object Instances as identified by an IOU Tracker. The bounding box of
- # the new Object will filled with a color for a (brief) visual indication,
- # with event data printed to the console for each
-
+
#`````````````````````````````````````````````````````````````````````````````
# Create a Format Label Action to remove the Object Label from view
# Note: the label can be disabled with the OSD API as well.
@@ -122,36 +133,7 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- #`````````````````````````````````````````````````````````````````````````````
- # Create two new RGBA fill colors to fill the bounding boxes of new objects
- retval = dsl_display_type_rgba_color_custom_new('solid-red',
- red=1.0, green=0.0, blue=0.0, alpha=1.0)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_display_type_rgba_color_custom_new('solid-white',
- red=1.0, green=1.0, blue=1.0, alpha=1.0)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- #`````````````````````````````````````````````````````````````````````````````
- # Create two new Actions to fill the bounding boxes, one for the PERSON class,
- # the other for the VEHICLE class.
- retval = dsl_ode_action_bbox_format_new('fill-person-action',
- border_width = 0,
- border_color = None,
- has_bg_color = True,
- bg_color = 'solid-red')
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_ode_action_bbox_format_new('fill-vehicle-action',
- border_width = 0,
- border_color = None,
- has_bg_color = True,
- bg_color = 'solid-white')
- if retval != DSL_RETURN_SUCCESS:
- break
-
# And a single action to print the event data to the console, which will be used
# by both our PERSON and VEHICLE Instance Trigers - created next
retval = dsl_ode_action_print_new('print-data', force_flush=False)
@@ -184,12 +166,10 @@ def main(args):
#`````````````````````````````````````````````````````````````````````````````
# Next, we add our Actions to our Triggers
- retval = dsl_ode_trigger_action_add_many('person-instance-trigger',
- actions=['fill-person-action', 'print-data', None])
+ retval = dsl_ode_trigger_action_add('person-instance-trigger', 'print-data')
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_ode_trigger_action_add_many('vehicle-instance-trigger',
- actions=['fill-vehicle-action', 'print-data', None])
+ retval = dsl_ode_trigger_action_add('vehicle-instance-trigger', 'print-data')
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/ode_intersection_min_max_dimensions.py b/examples/python/ode_intersection_min_max_dimensions.py
index 0ebd6890..3b78d640 100644
--- a/examples/python/ode_intersection_min_max_dimensions.py
+++ b/examples/python/ode_intersection_min_max_dimensions.py
@@ -22,6 +22,25 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example is used to demonstrate the Use of Two Intersection Triggers,
+# one for the Vehicle class the other for the Person class. A "Format BBox"
+# action will be used to shade the background of the Objects intersecting.
+# Person intersecting with Person and Vehicle intersecting with Vehicle.
+#
+# Min and Max Dimensions will set as addional criteria for the Preson and
+# Vehicle Triggers respecively
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -29,7 +48,7 @@
from dsl import *
import time
-uri_h265 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h265.mp4"
+uri_h265 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_qHD.mp4"
# Filespecs for the Primary GIE
primary_infer_config_file = \
@@ -91,22 +110,18 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- # This example is used to demonstrate the Use of Two Intersection Triggers, one for the Vehicle class
- # the other for the Person class. A "fill-object" action will be used to shade the background of
- # the Objects intersecting. Person intersecting with Person and Vehicle intersecting with Vehicle.
- #
- # Min and Max Dimensions will set as addional criteria for the Preson and Vehicle Triggers respecively
-
#```````````````````````````````````````````````````````````````````````````````````````````````````````````````
# Create a new RGBA color type
- retval = dsl_display_type_rgba_color_custom_new('opaque-red', red=1.0, blue=0.0, green=0.0, alpha=0.2)
+ retval = dsl_display_type_rgba_color_custom_new('opaque-red',
+ red=1.0, blue=0.0, green=0.0, alpha=0.2)
if retval != DSL_RETURN_SUCCESS:
break
- # Create a new Format BBox Action that will fill the Object's rectangle with a shade of red to indicate
- # intersection with one or more other Objects, i.e. ODE occurrence. The action will be used with both
- # the Person and Car class Ids.
+ # Create a new Format BBox Action that will fill the Object's rectangle with
+ # a shade of red to indicate intersection with one or more other Objects,
+ # i.e. ODE occurrence. The action will be used with both the Person and Car
+ # class Ids.
retval = dsl_ode_action_bbox_format_new('red-fill-action',
border_width = 0,
border_color = None,
@@ -134,8 +149,9 @@ def main(args):
break
#```````````````````````````````````````````````````````````````````````````````````````````````````````````````
- # Next, create the Person Intersection Trigger, and set a Minumum height as criteria, add the Actions to Fill
- # the Object and Print the ODE occurrence info to the console. Using a single class for testing.
+ # Next, create the Person Intersection Trigger, and set a Minumum height
+ # as criteria, add the Actions to Fill the Object and Print the ODE
+ # occurrence info to the console. Using a single class for testing.
retval = dsl_ode_trigger_intersection_new('person-intersection',
source = DSL_ODE_ANY_SOURCE,
class_id_a = PGIE_CLASS_ID_PERSON,
@@ -143,7 +159,8 @@ def main(args):
limit=DSL_ODE_TRIGGER_LIMIT_NONE )
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_ode_trigger_dimensions_min_set('person-intersection', min_width=0, min_height=70)
+ retval = dsl_ode_trigger_dimensions_min_set('person-intersection',
+ min_width=0, min_height=70)
if retval != DSL_RETURN_SUCCESS:
break
retval = dsl_ode_trigger_action_add_many('person-intersection', actions=
@@ -151,8 +168,9 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # Next, create the Vehicle Intersection Trigger, and set a Maximum height as criteria, add the Actions to Fill
- # the Object on ODE occurrence and Print the ODE occurrence info to the console.
+ # Next, create the Vehicle Intersection Trigger, and set a Maximum height
+ # as criteria, add the Actions to Fill the Object on ODE occurrence and
+ # Print the ODE occurrence info to the console.
retval = dsl_ode_trigger_intersection_new('vehicle-intersection',
source = DSL_ODE_ANY_SOURCE,
class_id_a = PGIE_CLASS_ID_VEHICLE,
@@ -160,19 +178,22 @@ def main(args):
limit = DSL_ODE_TRIGGER_LIMIT_NONE )
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_ode_trigger_dimensions_max_set('vehicle-intersection', max_width=0, max_height=80)
+ retval = dsl_ode_trigger_dimensions_max_set('vehicle-intersection',
+ max_width=0, max_height=80)
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_ode_trigger_action_add_many('vehicle-intersection', actions=
- ['red-fill-action', 'print-action', None])
+ retval = dsl_ode_trigger_action_add_many('vehicle-intersection',
+ actions= ['red-fill-action', 'print-action', None])
if retval != DSL_RETURN_SUCCESS:
break
#```````````````````````````````````````````````````````````````````````````````````````````````````````````````
# Next, create the Occurrence Trigger to Hide each Object's Display Text
- # New ODE occurrence Trigger to remove the Display Text and Border for all vehicles
- retval = dsl_ode_trigger_occurrence_new('every-object', source=DSL_ODE_ANY_SOURCE,
+ # New ODE occurrence Trigger to remove the Display Text and Border for
+ # all vehicles
+ retval = dsl_ode_trigger_occurrence_new('every-object',
+ source=DSL_ODE_ANY_SOURCE,
class_id=DSL_ODE_ANY_CLASS, limit=DSL_ODE_TRIGGER_LIMIT_NONE)
if retval != DSL_RETURN_SUCCESS:
break
@@ -196,7 +217,7 @@ def main(args):
break
- ############################################################################################
+ #############################################################################
#
# Create the remaining Pipeline components
diff --git a/examples/python/ode_largest_object_fill_surroundings.py b/examples/python/ode_largest_object_fill_surroundings.py
index d426ae71..2e51a2bc 100644
--- a/examples/python/ode_largest_object_fill_surroundings.py
+++ b/examples/python/ode_largest_object_fill_surroundings.py
@@ -22,6 +22,21 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates the used of a "Largest Object Trigger" and "Fill
+# Surroundings Action" to continuosly highlight the largest object in the Frame
+# as measured by bounding box area.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -46,9 +61,10 @@
PGIE_CLASS_ID_ROADSIGN = 3
# NOTE: filling the full frame with a blended alpha is a CPU intensive operation
-# Using a 30 fps file source requires us to reduce the size at the streammux output
-STREAMMUX_WIDTH = 1280
-STREAMMUX_HEIGHT = 720
+# You may need to reduce the size of the frames at the Streammuxer on cpu
+# constrained devices.
+STREAMMUX_WIDTH = DSL_1K_HD_WIDTH
+STREAMMUX_HEIGHT = DSL_1K_HD_HEIGHT
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720
@@ -96,12 +112,11 @@ def main(args):
while True:
# ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # The example demonstrates the used of a Larget Object Trigger and Fill Object Surroundings Action.
- # To continuosly hightly the larget object in the Frame as measured by bounding box area.
# ````````````````````````````````````````````````````````````````````````````````````````````````````````
# Create new RGBA color types
- retval = dsl_display_type_rgba_color_custom_new('opaque-black', red=0.0, blue=0.0, green=0.0, alpha=0.5)
+ retval = dsl_display_type_rgba_color_custom_new('opaque-black',
+ red=0.0, blue=0.0, green=0.0, alpha=0.5)
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/ode_line_cross_object_capture_overlay_image.py b/examples/python/ode_line_cross_object_capture_overlay_image.py
index b99c2143..c716aefc 100644
--- a/examples/python/ode_line_cross_object_capture_overlay_image.py
+++ b/examples/python/ode_line_cross_object_capture_overlay_image.py
@@ -22,20 +22,30 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
-# ------------------------------------------------------------------------------------
+################################################################################
+#
# This example demonstrates the use of an ODE Cross Trigger with an ODE Line Area
# and ODE Accumulator to accumulate occurrences of an object (person) crossing
# the line. The Accumulator uses an ODE Display Action to add the current counts
# of the IN and OUT crossings as display-metadata to each frame.
#
-# The bounding box and historical trace of each object - tracked by the Cross Trigger
-# - is assing a new random RGBA color and added as display-metadata to each frame.
+# The bounding box and historical trace of each object (tracked by the "Cross
+# Trigger") is assigned a new random RGBA color and added as display-metadata
+# to each frame.
#
# An ODE Capture Object Action with an Image Render Player is added to the Cross
# Trigger to capture and render an image of each object (person) that crosses the
-# line. Each image is display for 3 seconds. All files are written to the current
+# line. Each image is displayed for 3 seconds. All files are written to the current
# directory (configurable).
-
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A File Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
#!/usr/bin/env python
@@ -334,7 +344,7 @@ def main(args):
render_type = render_type,
offset_x = 700,
offset_y = 300,
- zoom = 200,
+ zoom = 100,
timeout = 3) # show indefinetely, until new image is captured
# Add the Termination listener callback to the Player
diff --git a/examples/python/ode_new_high_new_low_triggers_fill_frame.py b/examples/python/ode_new_high_new_low_triggers_fill_frame.py
index 3ae5ee89..0f00114a 100644
--- a/examples/python/ode_new_high_new_low_triggers_fill_frame.py
+++ b/examples/python/ode_new_high_new_low_triggers_fill_frame.py
@@ -22,6 +22,22 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates the use of the New-High and New-Low Count Triggers
+# that trigger on new high and low object counts respectively. The frame is
+# filled with a full color for a (brief) visual indication on each new occurrence.
+# A print Action is used to print the event data to the console as well.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -91,10 +107,6 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- # This example demonstrates the use of the New-High and New-Low Count Triggers
- # new Object Instances as identified by an IOU Tracker. The frame filled with a
- # color for a (brief) visual indication on New-High and New-Low object counts,
- # with event data printed to the console for each
#```````````````````````````````````````````````````````````````````````````````````
# Create a Format Label Action to remove the Object Label from view
diff --git a/examples/python/ode_occurrence_polygon_area_inclussion_exclusion.py b/examples/python/ode_occurrence_polygon_area_inclussion_exclusion.py
index 4ba16542..f0bdeab1 100644
--- a/examples/python/ode_occurrence_polygon_area_inclussion_exclusion.py
+++ b/examples/python/ode_occurrence_polygon_area_inclussion_exclusion.py
@@ -22,11 +22,40 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates the use of a Polygon Area for Inclusion
+# or Exclusion criteria for ODE occurrence.
+#
+# A "Polygon Display Type" is used to create either an ODE Area of Inclusion or
+# Exclusion based on the AREA_TYPE variable defined below.
+#
+# The ODE Area is then added to an ODE Occurrence Trigger to be used as criteria
+# for ODE occurrence.
+#
+# A "Format BBox Action" is used to fill each detected object that triggers
+# occurrence with an opaque red color for visual confirmation.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
+INCLUSION_AREA = 0
+EXCLUSION_AREA = 1
+
+AREA_TYPE = INCLUSION_AREA
+
#!/usr/bin/env python
import sys
from dsl import *
+
uri_h265 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h265.mp4"
# Filespecs for the Primary GIE
@@ -50,9 +79,6 @@
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720
-INCLUSION_AREA = 0
-EXCLUSION_AREA = 1
-
##
# Function to be called on XWindow KeyRelease event
##
@@ -95,10 +121,6 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- # This example demonstrates the use of a Polygon Area for Inclusion
- # or Exlucion critera for ODE occurrence. Change the variable below to try each.
-
- area_type = INCLUSION_AREA
#```````````````````````````````````````````````````````````````````````````````````
@@ -150,7 +172,7 @@ def main(args):
break
# create the ODE inclusion area to use as criteria for ODE occurrence
- if area_type == INCLUSION_AREA:
+ if AREA_TYPE == INCLUSION_AREA:
retval = dsl_ode_area_inclusion_new('polygon-area', polygon='polygon1',
show=True, bbox_test_point=DSL_BBOX_POINT_SOUTH)
if retval != DSL_RETURN_SUCCESS:
diff --git a/examples/python/ode_occurrence_record_sink_overlay_playback_send_email.py b/examples/python/ode_occurrence_record_sink_overlay_playback_send_email.py
deleted file mode 100644
index 8098fb16..00000000
--- a/examples/python/ode_occurrence_record_sink_overlay_playback_send_email.py
+++ /dev/null
@@ -1,443 +0,0 @@
-################################################################################
-# The MIT License
-#
-# Copyright (c) 2021-2023, Prominence AI, Inc.
-#
-# 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.
-################################################################################
-
-#!/usr/bin/env python
-
-import sys
-from dsl import *
-
-##########################################################################33####
-# IMPORTANT! it is STRONGLY advised that you create a new, free Gmail account --
-# that is seperate/unlinked from all your other email accounts -- strictly for
-# the purpose of sending ODE Event data uploaded from DSL. Then, add your
-# Personal email address as a "To" address to receive the emails.
-#
-# Gmail considers regular email programs (i.e Outlook, etc.) and non-registered
-# third-party apps to be "less secure". The email account used for sending email
-# must have the "Allow less secure apps" option turned on. Once you've created
-# this new account, you can go to the account settings and enable Less secure
-# app access. see https://myaccount.google.com/lesssecureapps
-#
-# CAUTION - Do not check sripts into your repo with valid credentials
-#
-#######################################################################
-user_name = 'my.smtps.server'
-password = 'my-server-pw'
-server_url = 'smtps://smtp.gmail.com:465'
-
-from_name = ''
-from_address = 'my.smtps.server'
-to_name = 'Joe Bloe'
-to_address = 'joe.blow@gmail.com'
-
-uri_h265 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h265.mp4"
-
-# Filespecs for the Primary GIE
-primary_infer_config_file = \
- '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_infer_primary.txt'
-primary_model_engine_file = \
- '/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet.etlt_b8_gpu0_int8.engine'
-
-# Filespec for the IOU Tracker config file
-iou_tracker_config_file = \
- '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_tracker_IOU.yml'
-
-PGIE_CLASS_ID_VEHICLE = 0
-PGIE_CLASS_ID_BICYCLE = 1
-PGIE_CLASS_ID_PERSON = 2
-PGIE_CLASS_ID_ROADSIGN = 3
-
-TILER_WIDTH = DSL_1K_HD_
-TILER_HEIGHT = DSL_1K_HD_HEIGHT
-WINDOW_WIDTH = TILER_WIDTH
-WINDOW_HEIGHT = TILER_HEIGHT
-
-##
-# Function to be called on XWindow KeyRelease event
-##
-def xwindow_key_event_handler(key_string, client_data):
- print('key released = ', key_string)
- if key_string.upper() == 'P':
- dsl_pipeline_pause('pipeline')
- elif key_string.upper() == 'R':
- dsl_pipeline_play('pipeline')
- elif key_string.upper() == 'Q' or key_string == '' or key_string == '':
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-##
-# Function to be called on XWindow Delete event
-##
-def xwindow_delete_event_handler(client_data):
- print('delete window event')
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-##
-# Function to be called on End-of-Stream (EOS) event
-##
-def eos_event_listener(client_data):
- print('Pipeline EOS event')
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-##
-# Function to be called on every change of Pipeline state
-##
-def state_change_listener(old_state, new_state, client_data):
- print('previous state = ', old_state, ', new state = ', new_state)
- if new_state == DSL_STATE_PLAYING:
- dsl_pipeline_dump_to_dot('pipeline', "state-playing")
-
-##
-# Function to be called on recording start and complete
-##
-def recording_event_listener(session_info_ptr, client_data):
- print(' *** Recording Event *** ')
-
- session_info = session_info_ptr.contents
-
- print('session_id: ', session_info.session_id)
-
- # If we're starting a new recording for this source
- if session_info.recording_event == DSL_RECORDING_EVENT_START:
- print('event: ', 'DSL_RECORDING_EVENT_START')
-
- # enable the always trigger showing the metadata for "recording in session"
- retval = dsl_ode_trigger_enabled_set('rec-on-trigger', enabled=True)
- if (retval != DSL_RETURN_SUCCESS):
- print('Enable trigger failed with error: ', dsl_return_value_to_string(retval))
-
- # Else, the recording session has ended for this source
- else:
- print('event: ', 'DSL_RECORDING_EVENT_END')
- print('filename: ', session_info.filename)
- print('dirpath: ', session_info.dirpath)
- print('duration: ', session_info.duration)
- print('container: ', session_info.container_type)
- print('width: ', session_info.width)
- print('height: ', session_info.height)
-
- # disable the always trigger showing the metadata for "recording in session"
- retval = dsl_ode_trigger_enabled_set('rec-on-trigger', enabled=False)
- if (retval != DSL_RETURN_SUCCESS):
- print('Disable always trigger failed with error: ', dsl_return_value_to_string(retval))
-
- # re-enable the one-shot trigger for the next "New Instance" of a person
- retval = dsl_ode_trigger_reset('bicycle-instance-trigger')
- if (retval != DSL_RETURN_SUCCESS):
- print('Failed to reset instance trigger with error:', dsl_return_value_to_string(retval))
-
- return None
-
-##
-# Function to be called on Player termination event
-##
-def player_termination_event_listener(client_data):
- print(' *** Video Playback Complete *** ')
-
- # reset the Player to close its rendering surface
- dsl_player_render_reset('video-player')
-
-def setup_smpt_mail():
-
- global server_url, user_name, password, from_name, from_address, \
- to_name, to_address
-
- retval = dsl_mailer_new('mailer')
- if retval != DSL_RETURN_SUCCESS:
- return retval
-
- retval = dsl_mailer_server_url_set('mailer', server_url)
- if retval != DSL_RETURN_SUCCESS:
- return retval
- retval = dsl_mailer_credentials_set('mailer' , user_name, password)
- if retval != DSL_RETURN_SUCCESS:
- return retval
- retval = dsl_mailer_address_from_set('mailer', from_name, from_address)
- if retval != DSL_RETURN_SUCCESS:
- return retval
- retval = dsl_mailer_address_to_add('mailer', to_name, to_address)
- if retval != DSL_RETURN_SUCCESS:
- return retval
-
- # (optional) queue a test message to be sent out when the main_loop starts
- return dsl_mailer_test_message_send('mailer')
-
-def main(args):
-
- # Since we're not using args, we can Let DSL initialize GST on first call
- while True:
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # This example is used to demonstrate the use of a First Occurrence Trigger and a Start Record Action
- # to control a Record Sink. A callback function, called on completion of the recording session, will
- # reset the Trigger allowing a new session to be started on next occurrence.
- # Addional actions are added to "Capture" the frame to an image-file and "Fill" the frame red as a visual marker.
- # A Video Render Player is added to the Capture Action to playback the video on record complete.
- # A Mailer is added to Capture Action to email information about the saved recording; name, location, etc.
-
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # Setup the SMTP Server URL, Credentials, and From/To addresss
- retval = setup_smpt_mail()
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # New Record-Sink that will buffer encoded video while waiting for the ODE trigger/action, defined below,
- # to start a new session on first occurrence. The default 'cache-size' and 'duration' are defined in
- # Setting the bit rate to 12 Mbps for 1080p
- retval = dsl_sink_record_new('record-sink', outdir="./", codec=DSL_CODEC_H265, container=DSL_CONTAINER_MKV,
- bitrate=2000000, interval=0, client_listener=recording_event_listener)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Update the cache size to 5 seconds .
- retval = dsl_sink_record_cache_size_set('record-sink', 5)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create the Video Render Player with a NULL file_path to be updated by the Record Sink
- dsl_player_render_video_new(
- name = 'video-player',
- file_path = None,
- render_type = DSL_RENDER_TYPE_3D,
- offset_x = 500,
- offset_y = 20,
- zoom = 50,
- repeat_enabled = False)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the Termination listener callback to the Player
- retval = dsl_player_termination_event_listener_add('video-player',
- client_listener=player_termination_event_listener, client_data=None)
- if retval != DSL_RETURN_SUCCESS:
- return
-
- # Add the Player to the Recorder Sink. The Sink will add/queue
- # the file_path to each video recording created.
- retval = dsl_sink_record_video_player_add('record-sink',
- player='video-player')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the Mailer to Recorder Sink. The Sink will use the Mailer to email information
- # -- file location, size, etc. -- on the completion each recorded video.
- retval = dsl_sink_record_mailer_add('record-sink',
- mailer = 'mailer',
- subject = 'ATTENTION: Bycicle Occurence!')
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # Create new RGBA color types
- retval = dsl_display_type_rgba_color_custom_new('opaque-red', red=1.0, blue=0.5, green=0.5, alpha=0.7)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_display_type_rgba_color_custom_new('full-red', red=1.0, blue=0.0, green=0.0, alpha=1.0)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_display_type_rgba_color_custom_new('full-white', red=1.0, blue=1.0, green=1.0, alpha=1.0)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_display_type_rgba_color_custom_new('opaque-black', red=0.0, blue=0.0, green=0.0, alpha=0.8)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_display_type_rgba_font_new('impact-20-white', font='impact', size=20, color='full-white')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create a new Text type object that will be used to show the recording in progress
- retval = dsl_display_type_rgba_text_new('rec-text', 'REC ', x_offset=10, y_offset=30,
- font='impact-20-white', has_bg_color=True, bg_color='opaque-black')
- if retval != DSL_RETURN_SUCCESS:
- break
- # A new RGBA Circle to be used to simulate a red LED light for the recording in progress.
- retval = dsl_display_type_rgba_circle_new('red-led', x_center=94, y_center=52, radius=8,
- color='full-red', has_bg_color=True, bg_color='full-red')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create a new Action to display the "recording in-progress" text
- retval = dsl_ode_action_display_meta_add_many_new('add-rec-on', display_types=
- ['rec-text', 'red-led', None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create an Always trigger to add the "REC" text meta-data to every frame when enabled.
- retval = dsl_ode_trigger_always_new('rec-on-trigger',
- source = DSL_ODE_ANY_SOURCE,
- when = DSL_ODE_PRE_OCCURRENCE_CHECK)
- if retval != DSL_RETURN_SUCCESS:
- return retval
-
- # Disable the trigger. Will be re-enabled on DSL_RECORDING_EVENT_START
- # and then disabled again on DSL_RECORDING_EVENT_END
- retval = dsl_ode_trigger_enabled_set('rec-on-trigger', enabled=False)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the display-meta add action to the Always trigger
- retval = dsl_ode_trigger_action_add('rec-on-trigger', action='add-rec-on')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create a Fill-Area Action as a visual indicator to identify
- #the frame that triggered the recording
- retval = dsl_ode_action_fill_frame_new('red-flash-action', 'opaque-red')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create a new Capture Action to capture the full-frame to jpeg image,
- # and save to file. The action will be triggered on firt instance of
- # a bicycle and will be saved to the current dir.
- retval = dsl_ode_action_capture_object_new('bicycle-capture-action', outdir="./")
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create a new Capture Action to start a new record session
- retval = dsl_ode_action_sink_record_start_new('start-record-action',
- record_sink='record-sink', start=5, duration=10, client_data=None)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # ````````````````````````````````````````````````````````````````````````````
- # Next, create the New Instance Trigger for the bicycle class.
- # We will reset the trigger in the recording complete callback
- retval = dsl_ode_trigger_instance_new('bicycle-instance-trigger',
- source=DSL_ODE_ANY_SOURCE, class_id=PGIE_CLASS_ID_BICYCLE, limit=1)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # set the "infer-done-only" criteria so we can capture the confidence level
- retval = dsl_ode_trigger_infer_done_only_set('bicycle-instance-trigger', True)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- retval = dsl_ode_action_print_new('print', force_flush=False)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # Add the actions to our Bicycle Occurence Trigger.
- retval = dsl_ode_trigger_action_add_many('bicycle-instance-trigger', actions=[
- 'red-flash-action',
- 'bicycle-capture-action',
- 'start-record-action',
- 'print',
- None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # New ODE Handler for our Trigger
- retval = dsl_pph_ode_new('ode-handler')
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_pph_ode_trigger_add_many('ode-handler', triggers=[
- 'bicycle-instance-trigger',
- 'rec-on-trigger',
- None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- ############################################################################################
- #
- # Create the remaining Pipeline components
-
- retval = dsl_source_uri_new('uri-source', uri_h265, is_live=False,
- skip_frames=0, drop_frame_interval=0)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Primary GIE using the filespecs above with interval = 1
- retval = dsl_infer_gie_primary_new('primary-gie',
- primary_infer_config_file, primary_model_engine_file, 1)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New IOU Tracker, setting operational width and hieght
- retval = dsl_tracker_new('iou-tracker', iou_tracker_config_file, 480, 272)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New OSD with text, clock and bbox display all enabled.
- retval = dsl_osd_new('on-screen-display',
- text_enabled=True, clock_enabled=True, bbox_enabled=True, mask_enabled=False)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # add our ODE Pad Probe Handle to the Sink Pad of the OSD
- retval = dsl_osd_pph_add('on-screen-display', 'ode-handler', DSL_PAD_SINK)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Window Sink, 0 x/y offsets and same dimensions as Tiled Display
- retval = dsl_sink_window_egl_new('egl-sink', 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the XWindow event handler functions defined above to the Window Sink
- retval = dsl_sink_window_key_event_handler_add('egl-sink',
- xwindow_key_event_handler, None)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_sink_window_delete_event_handler_add('egl-sink',
- xwindow_delete_event_handler, None)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add all the components to our pipeline - except for our second source and overlay sink
- retval = dsl_pipeline_new_component_add_many('pipeline',
- ['uri-source', 'primary-gie', 'iou-tracker',
- 'on-screen-display', 'egl-sink', 'record-sink', None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- ## Add the listener callback functions defined above
- retval = dsl_pipeline_state_change_listener_add('pipeline', state_change_listener, None)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_pipeline_eos_listener_add('pipeline', eos_event_listener, None)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Play the pipeline
- retval = dsl_pipeline_play('pipeline')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- dsl_main_loop_run()
- retval = DSL_RETURN_SUCCESS
- break
-
- # Print out the final result
- print(dsl_return_value_to_string(retval))
-
- # Cleanup all DSL/GST resources
- dsl_delete_all()
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv))
-
\ No newline at end of file
diff --git a/examples/python/ode_occurrence_trigger_with_heat_mapper.py b/examples/python/ode_occurrence_trigger_with_heat_mapper.py
index 06de3168..31aee516 100644
--- a/examples/python/ode_occurrence_trigger_with_heat_mapper.py
+++ b/examples/python/ode_occurrence_trigger_with_heat_mapper.py
@@ -22,6 +22,31 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates the use of an ODE Heat-Mapper added to an
+# ODE Occurrence trigger that triggers on every Person occurrence.
+# The occurrence data is mapped/ovelaid on everyframe. The example creates
+# all 5 predefined RGBA Color Palettes - Spectral, Red, Green, Blue, and Grey.
+# The ODE Heat-Mapper is created with the Spectral palette, but can be updated
+# at runtime by pressing the 'N' key.
+#
+# Several keys, bound to the Window Sink, are mapped to the ODE Heat Mapper services
+# - 'N' key maps to 'next' color palette with - dsl_ode_heat_mapper_color_palette_set
+# - 'C' key maps to 'clear' heat-map metrics - dsl_ode_heat_mapper_metrics_clear
+# - 'P' key maps to 'print' heat-map metrics - dsl_ode_heat_mapper_metrics_print
+# - 'L' key maps to 'log' heat-map metrics - dsl_ode_heat_mapper_metrics_log
+# - 'G' key maps to 'get' heat-map metrics - dsl_ode_heat_mapper_metrics_get
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -59,21 +84,6 @@
COLOR_PALETTES = [SPECTRAL_PALETTE, RED_PALETTE, GREEN_PALETTE, BLUE_PALETTE, GREY_PALETTE]
color_palette_index = DSL_COLOR_PREDEFINED_PALETTE_SPECTRAL
-# ------------------------------------------------------------------------------------
-# This example demonstrates the use of an ODE Heat-Mapper added to an
-# ODE Occurrence trigger that triggers on every Person occurrence.
-# The occurrence data is mapped/ovelaid on everyframe. The example creates
-# all 5 predefined RGBA Color Palettes - Spectral, Red, Green, Blue, and Grey.
-# The ODE Heat-Mapper is created with the Spectral palette, but can be updated
-# at runtime by pressing the 'N' key.
-#
-# Several keys, bound to the Window Sink, are mapped to the ODE Heat Mapper services
-# - 'N' key maps to 'next' color palette with - dsl_ode_heat_mapper_color_palette_set
-# - 'C' key maps to 'clear' heat-map metrics - dsl_ode_heat_mapper_metrics_clear
-# - 'P' key maps to 'print' heat-map metrics - dsl_ode_heat_mapper_metrics_print
-# - 'L' key maps to 'log' heat-map metrics - dsl_ode_heat_mapper_metrics_log
-# - 'G' key maps to 'get' heat-map metrics - dsl_ode_heat_mapper_metrics_get
-
##
# Function to be called on XWindow KeyRelease event
##
diff --git a/examples/python/ode_occurrence_trigger_with_monitor_action.py b/examples/python/ode_occurrence_trigger_with_monitor_action.py
index 675193ca..f6bc51f6 100644
--- a/examples/python/ode_occurrence_trigger_with_monitor_action.py
+++ b/examples/python/ode_occurrence_trigger_with_monitor_action.py
@@ -22,8 +22,9 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
-# ------------------------------------------------------------------------------------
-# This example demonstrates the use of an ODE Monitor Action -- added to an
+################################################################################
+#
+# This example demonstrates the use of an "ODE Monitor Action" -- added to an
# ODE Occurrence Trigger with the below criteria -- to monitor all
# ODE Occurrences
# - class id = PGIE_CLASS_ID_VEHICLE
@@ -31,7 +32,23 @@
# - minimum confidience = VEHICLE_MIN_CONFIDENCE
# - minimum width = VEHICLE_MIN_WIDTH
# - minimum height = VEHICLE_MIN_HEIGHT
-
+#
+# The ode_occurrence_monitor callback function (defined below) is added to the
+# "Monitor Action" to be called with the ODE Occurrence event data for
+# each detected object that meets the above criteria.
+#
+# The application can process the event data as needed. This examples simply
+# prints all of the event data to console.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - Two Secondary GST Inference Engines (SGIEs)
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
#!/usr/bin/env python
diff --git a/examples/python/ode_occurrence_uri_send_smtp_mail.py b/examples/python/ode_occurrence_uri_send_smtp_mail.py
deleted file mode 100644
index 796fb389..00000000
--- a/examples/python/ode_occurrence_uri_send_smtp_mail.py
+++ /dev/null
@@ -1,282 +0,0 @@
-################################################################################
-# The MIT License
-#
-# Copyright (c) 2019-2023, Prominence AI, Inc.
-#
-# 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.
-################################################################################
-
-##########################################################################33####
-# IMPORTANT! it is STRONGLY advised that you create a new, free Gmail account --
-# that is seperate/unlinked from all your other email accounts -- strictly for
-# the purpose of sending ODE Event data uploaded from DSL. Then, add your
-# Personal email address as a "To" address to receive the emails.
-#
-# Gmail considers regular email programs (i.e Outlook, etc.) and non-registered
-# third-party apps to be "less secure". The email account used for sending email
-# must have the "Allow less secure apps" option turned on. Once you've created
-# this new account, you can go to the account settings and enable Less secure
-# app access. see https://myaccount.google.com/lesssecureapps
-#
-# CAUTION - Do not check sripts into your repo with valid credentials
-#
-#######################################################################
-#!/usr/bin/env python
-
-import sys
-from dsl import *
-
-user_name = 'my.smtps.server'
-password = 'my-server-pw'
-server_url = 'smtps://smtp.gmail.com:465'
-
-from_name = ''
-from_address = 'my.smtps.server'
-to_name = 'Joe Bloe'
-to_address = 'joe.blow@gmail.com'
-
-uri_h265 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h265.mp4"
-
-# Filespecs for the Primary GIE
-primary_infer_config_file = \
- '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_infer_primary.txt'
-primary_model_engine_file = \
- '/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet.etlt_b8_gpu0_int8.engine'
-
-# Filespec for the IOU Tracker config file
-iou_tracker_config_file = \
- '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_tracker_IOU.yml'
-
-PGIE_CLASS_ID_VEHICLE = 0
-PGIE_CLASS_ID_BICYCLE = 1
-PGIE_CLASS_ID_PERSON = 2
-PGIE_CLASS_ID_ROADSIGN = 3
-
-WINDOW_WIDTH = DSL_STREAMMUX_DEFAULT_WIDTH
-WINDOW_HEIGHT = DSL_STREAMMUX_DEFAULT_HEIGHT
-
-##
-# Function to be called on XWindow KeyRelease event
-##
-def xwindow_key_event_handler(key_string, client_data):
- print('key released = ', key_string)
- if key_string.upper() == 'P':
- dsl_pipeline_pause('pipeline')
- elif key_string.upper() == 'R':
- dsl_pipeline_play('pipeline')
- elif key_string.upper() == 'Q' or key_string == '' or key_string == '':
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-##
-# Function to be called on XWindow Delete event
-##
-def xwindow_delete_event_handler(client_data):
- print('delete window event')
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-##
-# Function to be called on End-of-Stream (EOS) event
-##
-def eos_event_listener(client_data):
- print('Pipeline EOS event')
- dsl_pipeline_stop('pipeline')
- dsl_main_loop_quit()
-
-##
-# Function to be called on every change of Pipeline state
-##
-def state_change_listener(old_state, new_state, client_data):
- print('previous state = ', old_state, ', new state = ', new_state)
- if new_state == DSL_STATE_PLAYING:
- dsl_pipeline_dump_to_dot('pipeline', "state-playing")
-
-
-def setup_smpt_mail():
-
- global server_url, user_name, password, from_name, from_address, \
- to_name, to_address
-
- retval = dsl_mailer_new('mailer')
- if retval != DSL_RETURN_SUCCESS:
- return retval
-
- retval = dsl_mailer_server_url_set('mailer', server_url)
- if retval != DSL_RETURN_SUCCESS:
- return retval
- retval = dsl_mailer_credentials_set('mailer' , user_name, password)
- if retval != DSL_RETURN_SUCCESS:
- return retval
- retval = dsl_mailer_address_from_set('mailer', from_name, from_address)
- if retval != DSL_RETURN_SUCCESS:
- return retval
- retval = dsl_mailer_address_to_add('mailer', to_name, to_address)
- if retval != DSL_RETURN_SUCCESS:
- return retval
-
- # (optional) queue a test message to be sent out when main_loop starts
- return dsl_mailer_test_message_send('mailer')
-
-def main(args):
-
- # Since we're not using args, we can Let DSL initialize GST on first call
- while True:
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # This example is used to demonstrate the use of a First Occurrence Trigger and an Email Action
- # to send an emal using SMTP service. Addional actions are added to "Capture" the frame to an
- # image-file and "Fill" (flash) the frame red as a visual marker.
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # Setup the SMTP Server URL, Credentials, and From/To addresss
- retval = setup_smpt_mail()
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # Create new RGBA color types
- retval = dsl_display_type_rgba_color_custom_new('opaque-red', red=1.0, blue=0.5, green=0.5, alpha=0.7)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create a new Action to Queue an email
- retval = dsl_ode_action_email_new('email-action',
- mailer = 'mailer',
- subject = "Bicycle Occurrence!")
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create a Fill-Area Action as a visual indicator to identify the frame that triggered the recording
- retval = dsl_ode_action_fill_frame_new('red-flash-action', 'opaque-red')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Create a new Capture Action to capture the full-frame to jpeg image, and save to file.
- # The action will be triggered on firt occurrence of a bicycle and will be saved to the current dir.
- retval = dsl_ode_action_capture_frame_new('bicycle-capture-action', outdir="./")
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # Next, create the Bicycle Occurrence Trigger. We will reset the trigger in the recording complete callback
- retval = dsl_ode_trigger_occurrence_new('bicycle-occurrence-trigger',
- source=DSL_ODE_ANY_SOURCE, class_id=PGIE_CLASS_ID_BICYCLE, limit=1)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # Add the actions to our Bicycle Occurence Trigger.
- retval = dsl_ode_trigger_action_add_many('bicycle-occurrence-trigger', actions=[
- 'email-action',
- 'red-flash-action',
- 'bicycle-capture-action',
- None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # ````````````````````````````````````````````````````````````````````````````````````````````````````````
- # New ODE Handler for our Trigger
- retval = dsl_pph_ode_new('ode-handler')
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_pph_ode_trigger_add('ode-handler', trigger='bicycle-occurrence-trigger')
- if retval != DSL_RETURN_SUCCESS:
- break
- ############################################################################################
- #
- # Create the remaining Pipeline components
-
- retval = dsl_source_uri_new('uri-source', uri_h265, is_live=False,
- skip_frames=0, drop_frame_interval=0)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Primary GIE using the filespecs above with interval = 1
- retval = dsl_infer_gie_primary_new('primary-gie',
- primary_infer_config_file, primary_model_engine_file, 1)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New IOU Tracker, setting operational width and hieght
- retval = dsl_tracker_new('iou-tracker', iou_tracker_config_file, 480, 272)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New OSD with text, clock and bbox display all enabled.
- retval = dsl_osd_new('on-screen-display',
- text_enabled=True, clock_enabled=True, bbox_enabled=True, mask_enabled=False)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add our ODE Pad Probe Handler to the Sink pad of the OSD
- retval = dsl_osd_pph_add('on-screen-display',
- handler='ode-handler', pad=DSL_PAD_SINK)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # New Window Sink, 0 x/y offsets and dimensions
- retval = dsl_sink_window_egl_new('egl-sink', 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add the XWindow event handler functions defined above to the Window Sink
- retval = dsl_sink_window_key_event_handler_add('egl-sink',
- xwindow_key_event_handler, None)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_sink_window_delete_event_handler_add('egl-sink',
- xwindow_delete_event_handler, None)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Add all the components to our pipeline - except for our second source and overlay sink
- retval = dsl_pipeline_new_component_add_many('pipeline',
- ['uri-source', 'primary-gie', 'iou-tracker',
- 'on-screen-display', 'egl-sink', None])
- if retval != DSL_RETURN_SUCCESS:
- break
-
- ## Add the listener callback functions defined above
- retval = dsl_pipeline_state_change_listener_add('pipeline',
- state_change_listener, None)
- if retval != DSL_RETURN_SUCCESS:
- break
- retval = dsl_pipeline_eos_listener_add('pipeline', eos_event_listener, None)
- if retval != DSL_RETURN_SUCCESS:
- break
-
- # Play the pipeline
- retval = dsl_pipeline_play('pipeline')
- if retval != DSL_RETURN_SUCCESS:
- break
-
- dsl_main_loop_run()
- retval = DSL_RETURN_SUCCESS
- break
-
- # Print out the final result
- print(dsl_return_value_to_string(retval))
-
- # Cleanup all DSL/GST resources
- dsl_delete_all()
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv))
-
\ No newline at end of file
diff --git a/examples/python/ode_persistence_and_earliest_triggers_custom_labels.py b/examples/python/ode_persistence_and_earliest_triggers_custom_labels.py
index 34a070a4..5d29e414 100644
--- a/examples/python/ode_persistence_and_earliest_triggers_custom_labels.py
+++ b/examples/python/ode_persistence_and_earliest_triggers_custom_labels.py
@@ -28,27 +28,38 @@
import time
from dsl import *
-
-#-------------------------------------------------------------------------------------------
+
+################################################################################
#
# This script demonstrates the use of a Persistence Trigger to trigger on each Vehicle
-# that is tracked for more than one frame, to calculate the time of Object persistence
-# from the first frame the object was detected.
+# that is tracked for more than one frame -- to calculate the time of Object persistence
+# from the first frame the object was detected.
#
-# The Tracked Object's label is then "customed" to show the tracking Id and time of
+# The Tracked Object's label is then "customized" to show the tracking Id and time of
# persistence for each tracked Vehicle.
#
-# The script also creats an Earliest Trigger to trigger on the Vehicle that appeared
+# The script also creates an Earliest Trigger to trigger on the Vehicle that appeared
# the earliest -- i.e. the object with greatest persistence value -- and displays that
-# Object's persistence using a ODE Display Action.
-#
+# Object's persistence using an ODE Display Action.
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
# File path for the single File Source
file_path = '/opt/nvidia/deepstream/deepstream/samples/streams/sample_qHD.mp4'
-# Filespecs for the Primary Triton Inference Server (PTIS)
+# Filespecs for the Primary GIE
primary_infer_config_file = \
- '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app-triton/config_infer_plan_engine_primary.txt'
+ '/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/config_infer_primary.txt'
+primary_model_engine_file = \
+ '/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet.etlt_b8_gpu0_int8.engine'
+
# Filespec for the IOU Tracker config file
iou_tracker_config_file = \
@@ -331,8 +342,9 @@ def main(args):
if retval != DSL_RETURN_SUCCESS:
break
- # New Primary TIS using the filespec specified above, with interval = 0
- retval = dsl_infer_tis_primary_new('primary-tis', primary_infer_config_file, 1)
+ # New Primary GIE using the filespecs above with interval = 0
+ retval = dsl_infer_gie_primary_new('primary-gie',
+ primary_infer_config_file, primary_model_engine_file, 3)
if retval != DSL_RETURN_SUCCESS:
break
@@ -369,7 +381,7 @@ def main(args):
# Add all the components to a new pipeline
retval = dsl_pipeline_new_component_add_many('pipeline',
- ['uri-source', 'primary-tis', 'iou-tracker',
+ ['uri-source', 'primary-gie', 'iou-tracker',
'on-screen-display', 'egl-sink', None])
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/ode_persistence_trigger_fill_tracked_objects.py b/examples/python/ode_persistence_trigger_fill_tracked_objects.py
index cada974d..eaac1deb 100644
--- a/examples/python/ode_persistence_trigger_fill_tracked_objects.py
+++ b/examples/python/ode_persistence_trigger_fill_tracked_objects.py
@@ -22,6 +22,26 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example demonstrates the use of three ODE Persistence Triggers to trigger on
+# all tracked Objects - as identified by an IOU Tracker - that persist accross consecutive
+# frames for a specifid period of time. Each trigger specifies a range of minimum and
+# maximum times of persistence.
+# Trigger 1: 0 - 3 seconds - action = fill object with opaque green color
+# Trigger 2: 3 - 6 seconds - action = fill object with opaque yellow color
+# Trigger 3: 6 - 0 seconds - action = fill object with opaque red color
+# This will have the effect of coloring an object by its time in view
+#
+# The example uses a basic inference Pipeline consisting of:
+# - A URI Source
+# - Primary GST Inference Engine (PGIE)
+# - IOU Tracker
+# - On-Screen Display
+# - Window Sink
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -44,8 +64,8 @@
PGIE_CLASS_ID_PERSON = 2
PGIE_CLASS_ID_ROADSIGN = 3
-WINDOW_WIDTH = DSL_1K_HD_WIDTH
-WINDOW_HEIGHT = DSL_1K_HD_HEIGHT
+WINDOW_WIDTH = DSL_1K_HD_WIDTH // 2
+WINDOW_HEIGHT = DSL_1K_HD_HEIGHT // 2
##
# Function to be called on XWindow KeyRelease event
@@ -89,15 +109,6 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- # This example demonstrates the use of three ODE Persistence Triggers to trigger on
- # all tracked Objects - as identified by an IOU Tracker - that persist accross consecutive
- # frames for a specifid period of time. Each trigger specifies a range of minimum and
- # maximum times of persistence.
- # Trigger 1: 0 - 3 seconds - action = fill object with opaque green color
- # Trigger 2: 3 - 6 seconds - action = fill object with opaque yellow color
- # Trigger 3: 6 - 0 seconds - action = fill object with opaque red color
- # This will have the effect of coloring an object by its time in view
-
#```````````````````````````````````````````````````````````````````````````````````
# Create a Format Label Action to remove the Object Label from view
# Note: the label can be disabled with the OSD API as well.
diff --git a/examples/python/parallel_inference_on_selective_streams.py b/examples/python/parallel_inference_on_selective_streams.py
index 7afc1aae..9b13420d 100644
--- a/examples/python/parallel_inference_on_selective_streams.py
+++ b/examples/python/parallel_inference_on_selective_streams.py
@@ -42,7 +42,7 @@
#
# dsl_remuxer_branch_add('my-remuxer', 'my-branch-0')
#
-# In this example, 4 sources are added to the Pipeline:
+# In this example, 4 RTSP Sources are added to the Pipeline:
# - branch-1 will process streams [0,1]
# - branch-2 will process streams [1,2]
# - branch-3 will process streams [0,2,3]
@@ -67,13 +67,17 @@
from dsl import *
-file_path1 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_qHD.mp4"
-file_path2 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_ride_bike.mov"
-file_path3 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_walk.mov"
-file_path4 = "/opt/nvidia/deepstream/deepstream/samples/streams/sample_720p.mp4"
+
+# RTSP Source URI for AMCREST Camera
+amcrest_rtsp_uri = 'rtsp://username:password@192.168.1.108:554/cam/realmonitor?channel=1&subtype=0'
+
+# RTSP Source URI for HIKVISION Camera
+hikvision_rtsp_uri = 'rtsp://username:password@192.168.1.64:554/Streaming/Channels/101'
+
# All branches are currently using the same config and model engine files
-# which is pointless... The example will be updated to use multiple
+# which is pointless... The example will be updated to use multiple models
+# in a future release.
# Filespecs (Jetson and dGPU) for the Primary GIE
primary_infer_config_file_1 = \
@@ -141,22 +145,28 @@ def xwindow_key_event_handler(key_string, client_data):
def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
+ # All are using the same URI and need to be updated with your own
+ # unique camera URIs
while True:
- # 4new File Sources to produce streams 0 through 3
- retval = dsl_source_file_new('source-1', file_path1, True)
+ # 4 new RTSP Sources to produce streams 0 through 3
+ retval = dsl_source_rtsp_new('rtsp-source-0',
+ hikvision_rtsp_uri, DSL_RTP_ALL, 0, 0, 1000, 10)
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_source_file_new('source-2', file_path2, True)
+ retval = dsl_source_rtsp_new('rtsp-source-1',
+ hikvision_rtsp_uri, DSL_RTP_ALL, 0, 0, 1000, 10)
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_source_file_new('source-3', file_path3, True)
+ retval = dsl_source_rtsp_new('rtsp-source-2',
+ hikvision_rtsp_uri, DSL_RTP_ALL, 0, 0, 1000, 10)
if retval != DSL_RETURN_SUCCESS:
break
- retval = dsl_source_file_new('source-4', file_path4, True)
+ retval = dsl_source_rtsp_new('rtsp-source-3',
+ hikvision_rtsp_uri, DSL_RTP_ALL, 0, 0, 1000, 10)
if retval != DSL_RETURN_SUCCESS:
break
-
+
# ----------------------------------------------------------------------------
# Inference Branch #1 (b1) - single Primary GIE. Branch component
# is NOT required if using single component.
@@ -348,7 +358,7 @@ def main(args):
# ----------------------------------------------------------------------------
# Add all the components to our pipeline
retval = dsl_pipeline_new_component_add_many('pipeline',
- ['source-1', 'source-2', 'source-3', 'source-4',
+ ['rtsp-source-0', 'rtsp-source-1', 'rtsp-source-2', 'rtsp-source-3',
'remuxer', 'tiler', 'osd', 'window-sink', None])
if retval != DSL_RETURN_SUCCESS:
break
diff --git a/examples/python/rtsp_player_to_test_connections.py b/examples/python/rtsp_player_to_test_connections.py
index 16082f67..1d2d751f 100644
--- a/examples/python/rtsp_player_to_test_connections.py
+++ b/examples/python/rtsp_player_to_test_connections.py
@@ -22,6 +22,23 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# This example can be used to test your RTSP Source connection. It uses a simple
+# DSL Player with a single RTSP Source and Window Sink:
+#
+# There two example camera URI's below. One for AMCREST and one for HIKVISION.
+# update one of the URI's with your username and password, or add your own
+# URI format as needed.
+#
+# Ensure that the RTSP Source constructor is using the correct URI.
+#
+# The example registers handler callback functions to be notified of:
+# - key-release events
+# - delete-window events
+# - RTSP Source change-of-state events
+#
+################################################################################
#!/usr/bin/env python
import sys
@@ -70,14 +87,14 @@ def main(args):
# Since we're not using args, we can Let DSL initialize GST on first call
while True:
- # For each camera, create a new RTSP Source for the specific RTSP URI
+ # New RTSP Source for the specific RTSP URI
retval = dsl_source_rtsp_new('rtsp-source',
- uri = hikvision_rtsp_uri,
- protocol = DSL_RTP_ALL,
- skip_frames = 0,
- drop_frame_interval = 0,
- latency=1000,
- timeout=2)
+ uri = hikvision_rtsp_uri, # using hikvision URI defined above
+ protocol = DSL_RTP_ALL, # use RTP ALL protocl
+ skip_frames = 0, # decode every frame
+ drop_frame_interval = 0, # decode every frame
+ latency=1000, # 1000 ms of jitter buffer
+ timeout=10) # 10 second new buffer timeout
if (retval != DSL_RETURN_SUCCESS):
return retval
diff --git a/examples/python/segmentation_industrial.py b/examples/python/segmentation_industrial.py
index b23fe08f..e4afffc7 100644
--- a/examples/python/segmentation_industrial.py
+++ b/examples/python/segmentation_industrial.py
@@ -22,6 +22,28 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - URI Source to read a jpeg image file
+# - Primary GST Inference Engine (PGIE)
+# - Segmentation Visualizer
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+#
+# NOTE: The Primary GST Inference engine is configured for Industrial Segmentation.
+# The NVIDIA provided PGIE configuration file can be found at
+# /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-segmentation-test/
+#
+# The URI Source will push a single frame followed by an End of File (EOF) event.
+#
+################################################################################
+
#!/usr/bin/env python
import sys
@@ -37,7 +59,7 @@
'/opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-segmentation-test/dstest_segmentation_config_industrial.txt'
# Segmentation Visualizer output dimensions should (typically) match the
-# inference dimensions defined in segvisual_config_industrial.txt (512x512)
+# inference dimensions defined in dstest_segmentation_config_industrial.txt (512x512)
width = 512
height = 512
diff --git a/examples/python/segmentation_semantic.py b/examples/python/segmentation_semantic.py
index 12d080f1..c472ec09 100644
--- a/examples/python/segmentation_semantic.py
+++ b/examples/python/segmentation_semantic.py
@@ -22,17 +22,34 @@
# DEALINGS IN THE SOFTWARE.
################################################################################
+################################################################################
+#
+# The simple example demonstrates how to create a set of Pipeline components,
+# specifically:
+# - URI Source to read a jpeg image file
+# - Primary GST Inference Engine (PGIE)
+# - Segmentation Visualizer
+# - Window Sink
+# ...and how to add them to a new Pipeline and play
+#
+# The example registers handler callback functions with the Pipeline for:
+# - key-release events
+# - delete-window events
+#
+# NOTE: The Primary GST Inference engine is configured for Semantic Segmentation.
+# The NVIDIA provided PGIE configuration file can be found at
+# /opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-segmentation-test/
+#
+# The URI Source will push a single frame followed by an End of File (EOF) event.
+#
+################################################################################
+
#!/usr/bin/env python
import sys
import time
from dsl import *
-# NOTE: the below example video runs at 15/1 frame-rate which seems to be beyond
-# the limit of the PGIE to perform segmentation. This becomes apparent half-way
-# through the video when the Pipeline starts experiencing QOS issues. A slower
-# camera rate may be required.
-
# File path for the single File Source
file_path = '/opt/nvidia/deepstream/deepstream/samples/streams/sample_720p.jpg'
@@ -40,7 +57,7 @@
primary_infer_config_file = \
'/opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-segmentation-test/dstest_segmentation_config_semantic.txt'
# Segmentation Visualizer output dimensions should (typically) match the
-# inference dimensions defined in segvisual_config_semantic.txt (512x512)
+# inference dimensions defined in dstest_segmentation_config_semantic.txt (512x512)
width = 512
height = 512
diff --git a/src/DslOdeAction.cpp b/src/DslOdeAction.cpp
index 55f8cca4..3c0cdd40 100644
--- a/src/DslOdeAction.cpp
+++ b/src/DslOdeAction.cpp
@@ -1247,7 +1247,7 @@ namespace DSL
+ std::to_string(pFrameMeta->frame_num) + "
"));
body.push_back(std::string(" Width : "
+ std::to_string(pFrameMeta->source_frame_width) + "
"));
- body.push_back(std::string(" Heigh : "
+ body.push_back(std::string(" Height : "
+ std::to_string(pFrameMeta->source_frame_height) + "
"));
body.push_back(std::string(" Object Data : ------------------------
"));
body.push_back(std::string(" Occurrences : "
@@ -1504,7 +1504,7 @@ namespace DSL
m_ostream << " Pad Index : " << pFrameMeta->pad_index << "\n";
m_ostream << " Frame : " << pFrameMeta->frame_num << "\n";
m_ostream << " Width : " << pFrameMeta->source_frame_width << "\n";
- m_ostream << " Heigh : " << pFrameMeta->source_frame_height << "\n";
+ m_ostream << " Height : " << pFrameMeta->source_frame_height << "\n";
m_ostream << " Object Data : ------------------------" << "\n";
if (pObjectMeta)
@@ -1973,7 +1973,7 @@ namespace DSL
LOG_INFO(" Pad Index : " << pFrameMeta->pad_index);
LOG_INFO(" Frame : " << pFrameMeta->frame_num);
LOG_INFO(" Width : " << pFrameMeta->source_frame_width);
- LOG_INFO(" Heigh : " << pFrameMeta->source_frame_height );
+ LOG_INFO(" Height : " << pFrameMeta->source_frame_height );
LOG_INFO(" Object Data : ------------------------");
if (pObjectMeta)
@@ -2888,7 +2888,7 @@ namespace DSL
std::cout << " Pad Index : " << pFrameMeta->pad_index << "\n";
std::cout << " Frame : " << pFrameMeta->frame_num << "\n";
std::cout << " Width : " << pFrameMeta->source_frame_width << "\n";
- std::cout << " Heigh : " << pFrameMeta->source_frame_height << "\n";
+ std::cout << " Height : " << pFrameMeta->source_frame_height << "\n";
std::cout << " Object Data : ------------------------" << "\n";
if (pObjectMeta)