Drop frame but still have timestamp

Please provide complete information as applicable to your setup.

• Hardware Platform (Jetson / GPU) GPU/3070
• DeepStream Version 6.1.1
• JetPack Version (valid for Jetson only)
• TensorRT Version 8.6
• NVIDIA GPU Driver Version (valid for GPU only) 525
• Issue Type( questions, new requirements, bugs) deepstream,gstreamer
• How to reproduce the issue ? (This is for bugs. Including which sample app is using, the configuration files content, the command line used and other details for reproducing)
• Requirement details( This is for new requirement. Including the module name-for which plugin or for which sample application, the function description)

Hello:
I’m a deepstream developer. In my project, I use deepstream/gstreamer to read a mp4 video file ,drop some frame and write to mp4 file. But I find a problem that I can only drop frames, and timestamp still in file. Here is a example.

import sys
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GLib, Gst,GObject
import pyds
import cv2
import os

result_bitrate = 300000

class ConvertVideo(object):
    def __init__(self):
        Gst.init(None)

        self.result_filename = "draw.mp4"
        self.pipeline = Gst.Pipeline()
        self.src_name = "file://./origin.mp4"
        self.sink_sync = 0

    def drop_frame(self,frame_idx):
        if (int(frame_idx)>50 and int(frame_idx)<100) or (int(frame_idx)>200 and int(frame_idx)<250)  :
            return True
        else:
            return False


    def bus_call(self,bus, message, loop):
        t = message.type
        if t == Gst.MessageType.EOS:
            self.pipeline.send_event(Gst.Event.new_eos())
            sys.stdout.write("End-of-stream\n")
            self.loop.quit()
        elif t==Gst.MessageType.WARNING:
            err, debug = message.parse_warning()
            sys.stderr.write("Warning: %s: %s\n" % (err, debug))
        elif t == Gst.MessageType.ERROR:
            err, debug = message.parse_error()
            sys.stderr.write("Error: %s: %s\n" % (err, debug))
            loop.quit()
        return True

    def make_elm_or_print_err(self,factoryname, name, detail=""):
        """ Creates an element with Gst Element Factory make.
            Return the element  if successfully created, otherwise print
            to stderr and return None.
        """
        print("Creating", name)
        elm = Gst.ElementFactory.make(factoryname, name)
        if not elm:
            sys.stderr.write("Unable to create " + name + " \n")
            if detail:
                sys.stderr.write(detail)
        return elm

    def mulit_add(self,elements):
        for i in elements:
            self.pipeline.add(i)

    def multi_link(self,elements):
        # links mulit elements
        for i in range(len(elements)-1):
            elements[i].link(elements[i+1])

    def osd_sink_pad_buffer_probe(self,pad,info,u_data):
        frame_number=0

        gst_buffer = info.get_buffer()
        if not gst_buffer:
            print("Unable to get GstBuffer ")
            return

        batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(gst_buffer))
        l_frame = batch_meta.frame_meta_list

        while l_frame is not None:
            try:
                frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data)
            except StopIteration:
                break

            frame_number=frame_meta.frame_num
            

            should_drop = self.drop_frame(frame_number)
            if should_drop:
                return Gst.PadProbeReturn.DROP

            
            try:
                l_frame=l_frame.next
            except StopIteration:
                break
                
        return Gst.PadProbeReturn.OK	


    def cb_newpad(self,decodebin, decoder_src_pad,data):
        print("In cb_newpad\n")
        caps=decoder_src_pad.get_current_caps()
        if not caps:
            caps = decoder_src_pad.query_caps()
        gststruct=caps.get_structure(0)
        gstname=gststruct.get_name()
        source_bin=data
        features=caps.get_features(0)
        print("gstname=",gstname)
        if(gstname.find("video")!=-1):
            print("features=",features)
            if features.contains("memory:NVMM"):
                bin_ghost_pad=source_bin.get_static_pad("src")
                if not bin_ghost_pad.set_target(decoder_src_pad):
                    sys.stderr.write("Failed to link decoder src pad to source bin ghost pad\n")
            else:
                sys.stderr.write(" Error: Decodebin did not pick nvidia decoder plugin.\n")

    def decodebin_child_added(self,child_proxy,Object,name,user_data):
        print("Decodebin child added:", name)
        if(name.find("decodebin") != -1):
            Object.connect("child-added",self.decodebin_child_added,user_data)

        if "source" in name:
            source_element = child_proxy.get_by_name("source")
            if source_element.find_property('drop-on-latency') != None:
                Object.set_property("drop-on-latency", True)



    def create_source_bin(self,index,uri):
        print("Creating source bin")

        # Create a source GstBin to abstract this bin's content from the rest of the
        # pipeline
        bin_name="source-bin-%02d" %index
        print(bin_name)
        nbin=Gst.Bin.new(bin_name)
        if not nbin:
            sys.stderr.write(" Unable to create source bin \n")
        else:
            uri_decode_bin=Gst.ElementFactory.make("uridecodebin", "uri-decode-bin")
        if not uri_decode_bin:
            sys.stderr.write(" Unable to create uri decode bin \n")
        # We set the input uri to the source element
        uri_decode_bin.set_property("uri",uri)
        uri_decode_bin.connect("pad-added",self.cb_newpad,nbin)
        uri_decode_bin.connect("child-added",self.decodebin_child_added,nbin)
        Gst.Bin.add(nbin,uri_decode_bin)
        bin_pad=nbin.add_pad(Gst.GhostPad.new_no_target("src",Gst.PadDirection.SRC))
        if not bin_pad:
            sys.stderr.write(" Failed to add ghost pad in source bin \n")
            return None
        return nbin


    def create_pipeline(self):
        # 创建pipeline 
        self.pipeline = Gst.Pipeline()
        # 创建输入源
        source_bin = self.create_source_bin(0, self.src_name)
        # 创建视频转换(裁剪)
        nvvidconv_cut = self.make_elm_or_print_err("nvvideoconvert", "convertor_cut")
        streammux = self.make_elm_or_print_err("nvstreammux", "Stream-muxer")
        streammux.set_property('batch-size', 1)
        streammux.set_property('batched-push-timeout', 4000000)
        video = cv2.VideoCapture(self.src_name.split("file://")[-1])
        frame_width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
        frame_height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
        streammux.set_property('width', frame_width)
        streammux.set_property('height', frame_height)
        self.mulit_add([source_bin,nvvidconv_cut,streammux])
        source_bin.link(nvvidconv_cut)
        padname = "sink_0"
        sinkpad = streammux.get_request_pad(padname)
        srcpad = nvvidconv_cut.get_static_pad("src")
        srcpad.link(sinkpad)

        nvvidconv = self.make_elm_or_print_err("nvvideoconvert", "convertor")         # Use convertor to convert from NV12 to RGBA as required by nvosd
        nvosd = self.make_elm_or_print_err("nvdsosd", "onscreendisplay")              # Create OSD to draw on the converted RGBA buffer

        nvvidconv_postosd = self.make_elm_or_print_err("nvvideoconvert", "convertor_postosd")
        caps = self.make_elm_or_print_err("capsfilter", "filter")
        result_h264enc = self.make_elm_or_print_err("nvv4l2h264enc", "result_h264enc")
        result_h264enc.set_property("bitrate", result_bitrate)
        result_h264parser  = self.make_elm_or_print_err("h264parse", "result_h264-parse")
        result_container = self.make_elm_or_print_err("qtmux", "result_container")  # mkv  matroskamux
        result_filesink = self.make_elm_or_print_err("filesink","result_filesink")
        result_filesink.set_property("location",self.result_filename)
        result_filesink.set_property("sync", self.sink_sync)

        self.mulit_add([nvvidconv,nvosd,nvvidconv_postosd,caps,result_h264enc,result_h264parser,result_container,result_filesink])

        osdsinkpad = nvosd.get_static_pad("sink")
        osdsinkpad.add_probe(Gst.PadProbeType.BUFFER, self.osd_sink_pad_buffer_probe, 0)

        self.multi_link([streammux,nvvidconv,nvosd,nvvidconv_postosd,caps,result_h264enc,result_h264parser,result_container,result_filesink])


        self.loop = GLib.MainLoop()
        bus = self.pipeline.get_bus()
        bus.add_signal_watch()
        bus.connect ("message", self.bus_call, self.loop)



    def start(self):
        self.pipeline.set_state(Gst.State.PLAYING)
        self.loop.run()


if __name__ == "__main__":

    c1 = ConvertVideo()

    input_filename = 'input_video.mp4'
    c1.src_name = "file://"+os.path.join(os.getcwd(),input_filename)
    c1.result_filename = "output_video.mp4"

    c1.create_pipeline()
    c1.start()
    c1.pipeline.set_state(Gst.State.NULL)

The main function is drop_frame(),if return True, osd_sink_pad_buffer_probe will return Gst.PadProbeReturn.DROP.
In my expectation, for example, my input video is 10fps and 30s video length. The code will drop 50-100 frames and 200-250 frames. The result video should be 10fps and 20s video length . In fact result video still 30s and 5-10s and 20-25s is stopped.
What should I do to drop timestamp info?


Gstreamer will not rewrite the timestamp after you drop the frame. You need to rewrite the pts of the gstbuffer by yourself.

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