I want to calculate absolute timestamp from RTP and RTCP SR record

Hi Team,

Below code calculates absolute timestamp of RTSP frame from RTP and RTCP frames for remote stream. I want to calculate the same using local .mp4 video. So I want to modify the code to start using filesrc instead of rtspsrc but when I make this change then the code is not working. What changes do you suggest to make in this code.

Thanks and regards,
Kartik Choudhary

Source Code:

import gi
from gi.repository import GObject, Gst, GstRtp
gi.require_version('Gst', '1.0')

GObject.threads_init()
Gst.init(None)

ntp_time = 0  # Initialize NTP time
rtp_time = 0  # Initialize RTP time

class TimeValue:
    def __init__(self):
        self.tv_sec = 0
        self.tv_usec = 0

    def convert_ntp_to_datetime(self, ntp_timestamp):
        if ntp_timestamp>0:
            ntp_seconds, ntp_fraction = divmod(ntp_timestamp, 2**32)

            # Calculate the seconds and microseconds
            self.tv_sec = ntp_seconds - 2208988800  # Subtract the NTP epoch offset
            self.tv_usec = (ntp_fraction * 1000000) // 2**32

time_value_instance = TimeValue()

def on_new_manager_callback(rtspsrc, manager):
    sinkpad = manager.get_request_pad("recv_rtcp_sink_0")
    session = manager.emit("get-internal-session", 0)
    session.connect_after("on-receiving-rtcp", on_receiving_rtcp_callback)

def on_receiving_rtcp_callback(session, buffer: Gst.Buffer):
    global ntp_time, rtp_time
    rtcp_buffer = GstRtp.RTCPBuffer()
    res = GstRtp.RTCPBuffer.map(buffer, Gst.MapFlags.READ, rtcp_buffer)
    rtcp_packet = GstRtp.RTCPPacket()
    new_packet = rtcp_buffer.get_first_packet(rtcp_packet)

    while True:
        if rtcp_packet.get_type() == GstRtp.RTCPType.SR:
            si = rtcp_packet.sr_get_sender_info()
            ntp_time = si[1]
            rtp_time = si[2]
        if rtcp_packet.move_to_next() == False:
            break

def calculate_timestamp(pad, info):
    global ntp_time, rtp_time
    res, rtpBuff = GstRtp.RTPBuffer.map(info.get_buffer(), Gst.MapFlags.READ)
    time_value_instance.convert_ntp_to_datetime(ntp_time)
    rtp_diff = float(rtpBuff.get_timestamp() - rtp_time) / 90000.0
    timestamp = float(time_value_instance.tv_sec) + float(time_value_instance.tv_usec) / 1000000.0 + rtp_diff
    marker_bit = rtpBuff.get_marker()

    # In case multiple RTP packets arriving with same timestamp for single video frame, for the last frame the marker
    # bit is set to True to indicate complete video frame is recieved
    if marker_bit:
        print(f"timestamp: {timestamp}, NTP in SR: {ntp_time}, RTP in SR: {rtp_time}, time in RTP header: {rtpBuff.get_timestamp()}, marker bit:{marker_bit}") 

    return Gst.PadProbeReturn.OK

pipeline_str = "rtspsrc name = rtspsrc location=rtsp://<username>:<password>@<ipAddress>/stream0 ! rtph264depay name=depay ! appsink name=sink"

pipeline = Gst.parse_launch(pipeline_str)
if pipeline:
    rtspsrc = pipeline.get_by_name('rtspsrc')
    if rtspsrc:
        rtspsrc.connect("new-manager", on_new_manager_callback)

        depay = pipeline.get_by_name('depay')
        sinkpad = depay.get_static_pad('sink')
        probID = sinkpad.add_probe(Gst.PadProbeType.BUFFER, calculate_timestamp)
        pipeline.set_state(Gst.State.PLAYING)

        try:
            loop = GObject.MainLoop()
            loop.run()
        except KeyboardInterrupt:
            pipeline.set_state(Gst.State.NULL)
    else:
        print("rtspsrc is Null...")
else:
    print("Pipleline is Null...")
1 Like