NTP timestamp extraction keeps logging 1970-01-01 00:00:00.000

• Hardware Platform (Jetson / GPU) Jetson Xavier
• DeepStream Version DS 6.0
• JetPack Version (valid for Jetson only) 4.6 (L4T 32.6.1)
• TensorRT Version 8.0.1
• Gstreamer Version 1.16.3
**• Issue Type question

Hello everyone!

I am trying to use NTP timestamp retrieval by following the guide
(the 2nd option as I want to extract the NTP time that the frame was captured). I made all the necessary steps like setting attach-sys-ts to FALSE on nvstreammux and the attach-sys-ts-as-ntp config parameter to 0.
And also call configure_source_for_ntp_sync() function and pass the GstElement pointer to this API.

Also i checked that the RTCP packages are transmitted

4823558 1085.373752579 192.168.3.38 → 192.168.3.136 RTCP 126 Receiver Report   Source description   
4824764 1085.510605884 192.168.3.136 → 192.168.3.38 RTCP 122 Sender Report   Source description   
4846532 1088.304883973 192.168.3.136 → 192.168.3.38 RTCP 122 Sender Report   Source description   

and also with

 tshark -i eth0 -Y "rtcp" -V
User Datagram Protocol, Src Port: 50001, Dst Port: 34479
    Source Port: 50001
    Destination Port: 34479
    Length: 88
    Checksum: 0xf460 [unverified]
    [Checksum Status: Unverified]
    [Stream index: 3]
    [Timestamps]
        [Time since first frame: 26.693505419 seconds]
        [Time since previous frame: 1.188672908 seconds]
Real-time Transport Control Protocol (Sender Report)
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 0000 = Reception report count: 0
    Packet type: Sender Report (200)
    Length: 6 (28 bytes)
    Sender SSRC: 0x65da809a (1708818586)
    Timestamp, MSW: 3942942846 (0xeb04887e)
    Timestamp, LSW: 1343195187 (0x500f8833)
    [MSW and LSW as NTP timestamp: Dec 11, 2024 21:54:06.312736999 UTC]
    RTP timestamp: 2150277639
    Sender's packet count: 846757
    Sender's octet count: 1155592154

I also set the NTP server of the camera.

But when I try to access it

                rtsp_ntp_timestamp = frame_meta.ntp_timestamp

                ts_seconds = rtsp_ntp_timestamp / 1000000000
                rtsp_time = datetime.datetime.utcfromtimestamp(ts_seconds).strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]  

                self.logger.info(f"Frame Number: {frame_meta.frame_num}, RTSP NTP Timestamp: {rtsp_time}")

It keeps printing
Frame Number: n, RTSP NTP Timestamp: 1970-01-01 00:00:00.000

meaning that it returns 0

Do you have any ideas why this is happening or what should i check?
sample_logs.txt (22.2 KB)

Thanks a lot!

Refer to this FAQ

+  g_object_set (G_OBJECT (streammux), "live-source", 1, NULL);
+  g_object_set (G_OBJECT (streammux), "frame-duration", 0, NULL);
+  g_object_set (G_OBJECT (streammux), "attach-sys-ts", 0, NULL);

Thank you for your response.

I am getting

 [ERROR]:  TypeError("object of type `GstNvStreamMux' does not have property `frame-duration'

Also there is no such property when I do gst-inspect nvstreammux.

Factory Details:
  Rank                     primary (256)
  Long-name                Stream multiplexer
  Klass                    Generic
  Description              N-to-1 pipe stream multiplexing
  Author                   NVIDIA Corporation. Post on Deepstream for Tesla forum for any queries @ https://devtalk.nvidia.com/default/board/209/

Plugin Details:
  Name                     nvdsgst_multistream
  Description              NVIDIA Multistream mux/demux plugin
  Filename                 /usr/lib/aarch64-linux-gnu/gstreamer-1.0/deepstream/libnvdsgst_multistream.so
  Version                  6.0.0
  License                  Proprietary
  Source module            nvmultistream
  Binary package           NVIDIA Multistream Plugins
  Origin URL               http://nvidia.com/

GObject
 +----GInitiallyUnowned
       +----GstObject
             +----GstElement
                   +----GstNvStreamMux

Pad Templates:
  SINK template: 'sink_%u'
    Availability: On request
    Capabilities:
      video/x-raw(memory:NVMM)
                 format: { (string)NV12, (string)RGBA, (string)I420 }
                  width: [ 1, 2147483647 ]
                 height: [ 1, 2147483647 ]
              framerate: [ 0/1, 2147483647/1 ]
  
  SRC template: 'src'
    Availability: Always
    Capabilities:
      video/x-raw(memory:NVMM)
                 format: { (string)NV12, (string)RGBA, (string)I420 }
                  width: [ 1, 2147483647 ]
                 height: [ 1, 2147483647 ]
              framerate: [ 0/1, 2147483647/1 ]

Element has no clocking capabilities.
Element has no URI handling capabilities.

Pads:
  SRC: 'src'
    Pad Template: 'src'

Element Properties:
  attach-sys-ts       : If set to TRUE, system timestamp will be attached as ntp timestamp.
                        If set to FALSE, ntp timestamp from rtspsrc, if available, will be attached.
                        flags: readable, writable
                        Boolean. Default: true
  batch-size          : Maximum number of buffers in a batch
                        flags: readable, writable
                        Unsigned Integer. Range: 0 - 1024 Default: 0 
  batched-push-timeout: Timeout in microseconds to wait after the first buffer is available
                        to push the batch even if the complete batch is not formed.
                        Set to -1 to wait infinitely
                        flags: readable, writable
                        Integer. Range: -1 - 2147483647 Default: -1 
  buffer-pool-size    : Maximum number of buffers from muxer's output pool
                        flags: readable, writable
                        Unsigned Integer. Range: 4 - 1024 Default: 4 
  compute-hw          : Compute Scaling HW
                        flags: readable, writable, controllable
                        Enum "GstNvComputeHWType" Default: 0, "Default"
                           (0): Default          - Default, GPU for Tesla, VIC for Jetson
                           (1): GPU              - GPU
                           (2): VIC              - VIC
  enable-padding      : Maintain input aspect ratio when scaling by padding with black bands.
                        flags: readable, writable
                        Boolean. Default: false
  frame-num-reset-on-eos: Reset frame numbers to 0 for a source from which EOS is received (For debugging purpose only)
                        flags: readable, writable
                        Boolean. Default: false
  gpu-id              : Set GPU Device ID
                        flags: readable, writable
                        Unsigned Integer. Range: 0 - 4294967295 Default: 0 
  height              : Height of each frame in output batched buffer. This property MUST be set.
                        flags: readable, writable
                        Unsigned Integer. Range: 0 - 4294967295 Default: 0 
  interpolation-method: Set interpolation methods
                        flags: readable, writable, controllable
                        Enum "GstNvInterpolationMethod" Default: 1, "Bilinear"
                           (0): Nearest          - Nearest
                           (1): Bilinear         - Bilinear
                           (2): Algo-1           - GPU - Cubic, VIC - 5 Tap
                           (3): Algo-2           - GPU - Super, VIC - 10 Tap
                           (4): Algo-3           - GPU - LanzoS, VIC - Smart
                           (5): Algo-4           - GPU - Ignored, VIC - Nicest
                           (6): Default          - GPU - Nearest, VIC - Nearest
  live-source         : Boolean property to inform muxer that sources are live.
                        flags: readable, writable
                        Boolean. Default: false
  max-latency         : Additional latency in live mode to allow upstream to take longer to produce buffers for the current position (in nanoseconds)
                        flags: readable, writable
                        Unsigned Integer. Range: 0 - 4294967295 Default: 0 
  name                : The name of the object
                        flags: readable, writable
                        String. Default: "nvstreammux0"
  num-surfaces-per-frame: Max number of surfaces per frame
                        flags: readable, writable
                        Unsigned Integer. Range: 1 - 4 Default: 1 
  nvbuf-memory-type   : Type of NvBufSurface Memory to be allocated for output buffers
                        flags: readable, writable, changeable only in NULL or READY state
                        Enum "GstNvBufMemoryType" Default: 0, "nvbuf-mem-default"
                           (0): nvbuf-mem-default - Default memory allocated, specific to particular platform
                           (1): nvbuf-mem-cuda-pinned - Allocate Pinned/Host cuda memory
                           (2): nvbuf-mem-cuda-device - Allocate Device cuda memory
                           (3): nvbuf-mem-cuda-unified - Allocate Unified cuda memory
                           (4): nvbuf-mem-surface-array - Allocate Surface Array memory, applicable for Jetson
  parent              : The parent of the object
                        flags: readable, writable
                        Object of type "GstObject"
  sync-inputs         : Boolean property to force sychronization of input frames.
                        flags: readable, writable
                        Boolean. Default: false
  width               : Width of each frame in output batched buffer. This property MUST be set.
                        flags: readable, writable
                        Unsigned Integer. Range: 0 - 4294967295 Default: 0 

The other 2 properties are set.

Any ideas of how can I overcome this?

Thank you

Not noticing that you are using a legacy version, xavier should be able to upgrade to DS-6.4 with Jetpack 5.1.2 GA

It looks like you are using pyds, but pyds doesn’t seem to support configure_source_for_ntp_sync in version 1.1.0

Did you add the python binding yourself?

If you upgrade to DS-6.4, this sample should show how to use ntp time

Yes it is true that i am using DeepStream Version DS 6.0 which I am planning to update in the future, but for now I can not.
But I am using pyds 1.1.8 meant for DS 6.3 so I have configure_source_for_ntp_sync available.
Is there a way to get the timestamp with these versions?

Do not use pyds-1.1.8, they may be incompatible. If you must use DS-6.0, please migrate the code to pyds-1.1.0 and recompile and install it.

Please make sure the above sample can work first

I tried with pyds-1.1.0 and they do not work. The pyds version I used before trying to extract the timestamp was pyds-1.1.3 because pyds-1.1.0 are for python 3.6 while my system works with 3.8. pyds-1.1.3 dont have the configure_source_for_ntp_sync, and I also tried to use ctypes like here but it caused a exit code -11 core dumped. Also the frame duration is not available in either of them. How can i proceed?

Port the code of pyds-1.1.8 to pyds-1.1.0, and then compile pyds yourself according to the steps in the document

I will try this, but can you tell me how this will help me solve my problem?

It is currently impossible to confirm whether this problem is caused by incompatible pyds, so we need to troubleshoot this problem first.

Ok.
Could you please provide a quick guide on what do you mean and how to “Port the code of pyds-1.1.8 to pyds-1.1.0, and then compile pyds yourself” ?
Can’t I do it using the generated pip wheel?
Thank you

If the ntp time is received correctly, there will be no problem
Since I don’t have a DS-6.0 xavier, the following example is based on the DS-6.0 x86 docker image

Save the following script as pyds.sh

#!/usr/bin/env bash

set -e

apt update
apt install -y git python-dev python3 python3-pip python3.8-dev cmake g++ build-essential \
    libglib2.0-dev libglib2.0-dev-bin python-gi-dev libtool m4 autoconf automake

rm -rf /usr/bin/python3
ln -s /usr/bin/python3.6 /usr/bin/python3

cd /opt/nvidia/deepstream/deepstream/sources

git clone https://github.com/NVIDIA-AI-IOT/deepstream_python_apps.git -b v1.1.0
cd deepstream_python_apps
cp /opt/nvidia/deepstream/deepstream/out.patch .
git apply out.patch

git clone https://github.com/GStreamer/gst-python.git 3rdparty/gst-python

cd 3rdparty/gst-python
git checkout 1a8f48a
./autogen.sh PYTHON=python3
./configure PYTHON=python3
make
make install
cd -

git clone https://github.com/pybind/pybind11.git 3rdparty/pybind11 -b v2.3.0

mkdir bindings/build
cd bindings/build 
cmake ../
make -j
pip3 uninstall pyds
pip3 install ./pyds-1.1.0-*.whl
cd -

Save the following patch as out.patch

diff --git a/apps/deepstream-rtsp-in-rtsp-out/deepstream_test1_rtsp_in_rtsp_out.py b/apps/deepstream-rtsp-in-rtsp-out/deepstream_test1_rtsp_in_rtsp_out.py
index a7de46d..4e036dc 100644
--- a/apps/deepstream-rtsp-in-rtsp-out/deepstream_test1_rtsp_in_rtsp_out.py
+++ b/apps/deepstream-rtsp-in-rtsp-out/deepstream_test1_rtsp_in_rtsp_out.py
@@ -31,6 +31,7 @@ gi.require_version("GstRtspServer", "1.0")
 from gi.repository import GObject, Gst, GstRtspServer, GLib
 import configparser
 
+import datetime
 import argparse
 
 from common.FPS import GETFPS
@@ -56,7 +57,7 @@ pgie_classes_str = ["Vehicle", "TwoWheeler", "Person", "RoadSign"]
 # and update params for drawing rectangle, object information etc.
 
 
-def tiler_src_pad_buffer_probe(pad, info, u_data):
+def pgie_src_pad_buffer_probe(pad, info, u_data):
     frame_number = 0
     num_rects = 0
     gst_buffer = info.get_buffer()
@@ -112,6 +113,10 @@ def tiler_src_pad_buffer_probe(pad, info, u_data):
             obj_counter[PGIE_CLASS_ID_PERSON],
         )
 
+        if ts_from_rtsp:
+            ts = frame_meta.ntp_timestamp/1000000000 # Retrieve timestamp, put decimal in proper position for Unix format
+            print("RTSP Timestamp:",datetime.datetime.utcfromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')) # Convert timestamp to UTC
+
         # Get frame rate through this probe
         fps_streams["stream{0}".format(frame_meta.pad_index)].get_fps()
         try:
@@ -155,6 +160,10 @@ def decodebin_child_added(child_proxy, Object, name, user_data):
     if name.find("decodebin") != -1:
         Object.connect("child-added", decodebin_child_added, user_data)
 
+    if ts_from_rtsp:
+        if name.find("source") != -1:
+            pyds.configure_source_for_ntp_sync(hash(Object))
+
 
 def create_source_bin(index, uri):
     print("Creating source bin")
@@ -310,6 +319,9 @@ def main(args):
     streammux.set_property("batch-size", 1)
     streammux.set_property("batched-push-timeout", 4000000)
 
+    if ts_from_rtsp:
+        streammux.set_property("attach-sys-ts", 0)
+
     if gie=="nvinfer":
         pgie.set_property("config-file-path", "dstest1_pgie_config.txt")
     else:
@@ -362,6 +374,12 @@ def main(args):
     bus.add_signal_watch()
     bus.connect("message", bus_call, loop)
 
+    pgie_src_pad=pgie.get_static_pad("src")
+    if not pgie_src_pad:
+        sys.stderr.write(" Unable to get src pad \n")
+    else:
+        pgie_src_pad.add_probe(Gst.PadProbeType.BUFFER, pgie_src_pad_buffer_probe, 0)
+
     # Start streaming
     rtsp_port_num = 8554
 
@@ -403,6 +421,8 @@ def parse_args():
                   help="RTSP Streaming Codec H264/H265 , default=H264", choices=['H264','H265'])
     parser.add_argument("-b", "--bitrate", default=4000000,
                   help="Set the encoding bitrate ", type=int)
+    parser.add_argument("--rtsp-ts", action="store_true", default=False, dest='rtsp_ts', help="Attach NTP timestamp from RTSP source",
+    )
     # Check input arguments
     if len(sys.argv)==1:
         parser.print_help(sys.stderr)
@@ -412,10 +432,12 @@ def parse_args():
     global bitrate
     global stream_path
     global gie
+    global ts_from_rtsp
     gie = args.gie
     codec = args.codec
     bitrate = args.bitrate
     stream_path = args.input
+    ts_from_rtsp = args.rtsp_ts
     return stream_path
 
 if __name__ == '__main__':
diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt
index 5bf88e4..0c0232c 100644
--- a/bindings/CMakeLists.txt
+++ b/bindings/CMakeLists.txt
@@ -99,7 +99,7 @@ function(add_ds_lib libname)
         target_link_libraries(pyds ${libname})
 endfunction()
 
-foreach(nvds_lib nvds_osd nvds_meta nvds_infer nvdsgst_meta nvbufsurface nvbufsurftransform)
+foreach(nvds_lib nvds_osd nvds_meta nvds_infer nvdsgst_meta nvbufsurface nvbufsurftransform nvdsgst_helper)
         add_ds_lib(${nvds_lib})
 endforeach()
 
diff --git a/bindings/src/bindfunctions.cpp b/bindings/src/bindfunctions.cpp
index 1397f2b..747d609 100644
--- a/bindings/src/bindfunctions.cpp
+++ b/bindings/src/bindfunctions.cpp
@@ -17,6 +17,7 @@
 
 #include "bind_string_property_definitions.h"
 #include "bindfunctions.hpp"
+#include "nvdsgstutils.h"
 
 namespace py = pybind11;
 using namespace std;
@@ -741,5 +742,12 @@ namespace pydeepstream {
               },
               "data"_a,
               pydsdoc::methodsDoc::get_segmentation_masks);
+        m.def("configure_source_for_ntp_sync",
+            [](size_t src_elem) {
+                  auto *element = reinterpret_cast<GstElement *>(src_elem);
+                  configure_source_for_ntp_sync(element);
+                  return;
+              },
+              "src_elem"_a);
     }
 }
\ No newline at end of file

Put them at /opt/nvidia/deepstream/deepstream, then run ./pyds.sh
pyds-1.1.0 will be installed correctly. If there are permission issues, please add sudo.

Then run the deepstream_test1_rtsp_in_rtsp_out.py

pip3 install datetime
cd /opt/nvidia/deepstream/deepstream-6.0/sources/deepstream_python_apps/apps/deepstream-rtsp-in-rtsp-out
python3 deepstream_test1_rtsp_in_rtsp_out.py -i rtsp://xxxxx:8554/mystream --rtsp-ts

After receiving ntp time, I got the correct log

Frame Number= 672 Number of Objects= 21 Vehicle_count= 19 Person_count= 2
RTSP Timestamp: 2024-12-13 09:07:53
Frame Number= 673 Number of Objects= 23 Vehicle_count= 20 Person_count= 2
RTSP Timestamp: 2024-12-13 09:07:53
Frame Number= 674 Number of Objects= 22 Vehicle_count= 20 Person_count= 2
RTSP Timestamp: 2024-12-13 09:07:53
Frame Number= 675 Number of Objects= 20 Vehicle_count= 18 Person_count= 2
RTSP Timestamp: 2024-12-13 09:07:53
Frame Number= 676 Number of Objects= 18 Vehicle_count= 16 Person_count= 2
RTSP Timestamp: 2024-12-13 09:07:53
^CFrame Number= 677 Number of Objects= 16 Vehicle_count= 14 Person_count= 2
RTSP Timestamp: 2024-12-13 09:07:53
Frame Number= 678 Number of Objects= 14 Vehicle_count= 12 Person_count= 2
RTSP Timestamp: 2024-12-13 09:07:53
Frame Number= 679 Number of Objects= 16 Vehicle_count= 14 Person_count= 2
RTSP Timestamp: 2024-12-13 09:07:53

You have been very helpful. I will test this and let you know

I found a solution after all but PLEASE take a llook on the following because I think there is an issue on your code.

First of all above there is the corrected pyds.sh that got me into the step.

make -j$(nproc) VERBOSE=1
#!/usr/bin/env bash

set -e

apt update
apt install -y python3-gi python3-dev python3-gst-1.0 python-gi-dev git python-dev \
    python3 python3-pip python3.8-dev cmake g++ build-essential libglib2.0-dev \
    libglib2.0-dev-bin python-gi-dev libtool m4 autoconf automake


cd /opt/nvidia/deepstream/deepstream/sources

git clone https://github.com/NVIDIA-AI-IOT/deepstream_python_apps.git -b v1.1.0
cd deepstream_python_apps
cp /opt/nvidia/deepstream/deepstream/out.patch .
git apply out.patch

git clone https://github.com/GStreamer/gst-python.git 3rdparty/gst-python
apt update
cd 3rdparty/gst-python
git checkout 1a8f48a
./autogen.sh 
./configure 
make
make install
cd -

git clone https://github.com/pybind/pybind11.git 3rdparty/pybind11 -b v2.3.0
rm -rf bindings/build
mkdir bindings/build
cd bindings/build 
cmake ..  -DPYTHON_MAJOR_VERSION=3 -DPYTHON_MINOR_VERSION=8 \
    -DPIP_PLATFORM=linux_aarch64 -DDS_PATH=/opt/nvidia/deepstream/deepstream-6.0/
make -j$(nproc) VERBOSE=1
pip3 uninstall pyds
pip3 install ./pyds-1.1.0-*.whl
cd -

On this step I had the following error:

cc1plus: error: too many filenames given.  Type cc1plus --help for usage
cc1plus: fatal error: CMakeFiles/pyds.dir/src/pyds.cpp.d: No such file or directory
compilation terminated.
make[2]: *** [CMakeFiles/pyds.dir/build.make:76: CMakeFiles/pyds.dir/src/pyds.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
cc1plus: error: too many filenames given.  Type cc1plus --help for usage
cc1plus: fatal error: CMakeFiles/pyds.dir/src/bindfunctions.cpp.d: No such file or directory
compilation terminated.

In multiple files.

The solution which eventually got the compilation to work is to change the wrong -o3 optimization spelling to -O3 inside the

/opt/nvidia/deepstream/deepstream/sources/deepstream_python_apps/bindings/CMakeLists.txt

-add_compile_options(-Wall -Wextra -pedantic -o3)
+add_compile_options(-Wall -Wextra -pedantic -03)

After this I was able to call the

        pyds.configure_source_for_ntp_sync(hash(rtspsrc))

which has the correct timestamp but unfortunately it causes the pipeline to stop after a few seconds, maybe due to buffer not unmaping (this is a guess), I don not know if I will continue investigating this or I will take the NTP timestamp with traditional Gstreamer methods.

PLEASE take a look at the above to see if it is indeed an issue. If it is and you find a patch or an orginized and robust solution to have configure_source_for_ntp_sync running please feel free to share. I am open to any ideas/conversation

As I said above, I don’t have a xavier with DS-6.0 installed, so I chose the same version for the x86 platform for testing.

There is no difference between make -j and make -j$(nproc). there won’t be any problems here,

O3 is the compilation option of gcc. Please do not modify it. 03 is an unrecognized option.

If you just run the sample, will there be any problems?

I am sorry for the late response.

Without deleting the -o3 or changing it to -O3 I can not pass the make step, because of the error I provided above.

Thank you

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.