Please provide complete information as applicable to your setup.
• Hardware Platform (Jetson / GPU) A100
• DeepStream Version 9.0
• JetPack Version (valid for Jetson only)
• TensorRT Version deepstream installation
• NVIDIA GPU Driver Version (valid for GPU only) 590
• Issue Type( questions, new requirements, bugs)
• 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)
i use x264enc in my a100 pipeline because it doesn’t have any nvEnc but i think i get backpresure because of that, can you help me in this?
this is the bin i used in pipeline for output(please don’t ask to give you other section of pipeline and i link and add them to other sections and itself to )
the problem is i think i get some kind of back presure from this bin and also it has some freezing in output
please help me to fix this
outputUserInfoMessage(f"x264enc selected for webrtc with gpuId={gpu_id}", username)
# -----------------------------------------------------------------------------
# queue0 — RAW frames. This is the ONLY queue allowed to leak.
# Dropping a raw frame costs nothing downstream. Dropping an *encoded* frame
# breaks the reference chain and corrupts every frame until the next IDR.
# -----------------------------------------------------------------------------
queue0, unique_id = ElementMaker().make_element(
element_name="queue", node=node, username=username)
queue0.set_property("max-size-buffers", 5)
queue0.set_property("max-size-time", 0)
queue0.set_property("max-size-bytes", 0)
queue0.set_property("leaky", 2) # downstream
elements.append(queue0)
# -----------------------------------------------------------------------------
# NVMM -> system memory.
# PINNED, not UNIFIED: x264enc reads this on the CPU. On a PCIe dGPU (A100)
# unified memory demand-pages device->host on every CPU touch, which is a
# per-frame stall. Pinned gives one bulk DMA instead.
# -----------------------------------------------------------------------------
nvvidconv_postosd, unique_id = ElementMaker().make_element(
element_name="nvvideoconvert", node=node, username=username)
nvvidconv_postosd.set_property("nvbuf-memory-type", int(pyds.NVBUF_MEM_CUDA_PINNED))
nvvidconv_postosd.set_property(Parameters._PrivateProperties.GPU_ID.value, gpu_id)
nvvidconv_postosd.set_property("output-buffers", 8)
elements.append(nvvidconv_postosd)
capsfilter, unique_id = ElementMaker().make_element(
element_name="capsfilter", node=node, username=username)
capsfilter.set_property("caps", Gst.Caps.from_string("video/x-raw, format=I420, width=1920, height=1080,framerate=30/1"))
elements.append(capsfilter)
# -----------------------------------------------------------------------------
# x264enc
# -----------------------------------------------------------------------------
x264enc, unique_id = ElementMaker().make_element(
element_name="x264enc", node=node, username=username)
if not x264enc:
sys.stderr.write(" Unable to create x264enc \n")
len_inputs = len(find_elements_by_subtype(
graph_copy, [NodeOperation.VIDEO_DECODE, NodeOperation.MULTI_IMAGE_DECODE]))
# NOTE: x264enc "bitrate" is in kbit/s. vp8enc "target-bitrate" was bit/s.
# Passing 4_000_000 here would request 4 Gbit/s.
bitrate_kbps = min(4000, 800 + (200 * len_inputs)) # 16 inputs -> 4000 kbps
x264enc.set_property("bitrate", bitrate_kbps)
x264enc.set_property("speed-preset", 3) # veryfast
x264enc.set_property("tune", 0x00000004) # zerolatency
x264enc.set_property("pass", 0) # CBR
# vbv-buf-capacity is THE critical rate-control setting. Default 600 ms lets a
# frame overshoot enormously before RC reacts — that is what made VP8 keyframes
# too big to survive transit. 200 ms bounds the burst.
x264enc.set_property("vbv-buf-capacity", 200)
x264enc.set_property("key-int-max", 30) # 2 s ceiling; PLI drives the rest
x264enc.set_property("bframes", 0) # B-frames add reorder latency
x264enc.set_property("b-adapt", False)
x264enc.set_property("cabac", False) # MUST be False for constrained-baseline
x264enc.set_property("sliced-threads", True) # no frame-level threading latency
x264enc.set_property("sync-lookahead", 0)
x264enc.set_property("rc-lookahead", 0)
x264enc.set_property("threads", 8)
x264enc.set_property("aud", False)
x264enc.set_property("byte-stream", True)
x264enc.set_property("insert-vui", True)
# Enable ONLY if corruption still spreads across whole frames (Test 3).
# Caps each slice to one RTP packet, so a lost packet damages a band not a frame.
# Verified on 1.24: coexists with sliced-threads=True, no warning emitted.
elements.append(x264enc)
# Profile must match cabac=False. If these disagree, caps negotiation fails.
enc_capsfilter, unique_id = ElementMaker().make_element(
element_name="capsfilter", node=node, username=username)
enc_capsfilter.set_property("caps", Gst.Caps.from_string(
"video/x-h264,profile=constrained-baseline,stream-format=byte-stream,alignment=au"))
elements.append(enc_capsfilter)
# -----------------------------------------------------------------------------
# h264parse — config-interval=-1 repeats SPS/PPS with every IDR.
# Without this, losing the one initial parameter set means Chrome can never
# decode again, no matter how many PLIs it sends. Permanent black stream.
# -----------------------------------------------------------------------------
h264parse, unique_id = ElementMaker().make_element(
element_name="h264parse", node=node, username=username)
h264parse.set_property("config-interval", -1)
elements.append(h264parse)
# -----------------------------------------------------------------------------
# queue1 — ENCODED frames. NOT leaky, time-bounded.
# When it fills: x264enc blocks -> queue0 leaks raw frames. FPS dips under
# pressure, bitstream stays intact. This is the correct backpressure cascade.
# It only works because CBR + vbv-buf-capacity bound the output rate.
# -----------------------------------------------------------------------------
# queue1, unique_id = ElementMaker().make_element(
# element_name="queue", node=node, username=username)
# queue1.set_property("max-size-buffers", 10)
# queue1.set_property("max-size-bytes", 0)
# queue1.set_property("max-size-time", 0) # 200 ms
# # queue1.set_property("leaky", 2) # no leak
# elements.append(queue1)
# -----------------------------------------------------------------------------
# rtph264pay
# -----------------------------------------------------------------------------
rtph264pay, unique_id = ElementMaker().make_element(
element_name="rtph264pay", node=node, username=username)
if not rtph264pay:
sys.stderr.write(" Unable to create rtph264pay \n")
rtph264pay.set_property("config-interval", -1) # SPS/PPS before every IDR
rtph264pay.set_property("aggregate-mode", 1) # zero-latency STAP-A
rtph264pay.set_property("mtu", 1200)
rtph264pay.set_property("pt", 96)
rtph264pay.set_property("auto-header-extension", True)
elements.append(rtph264pay)
rtp_capsfilter, unique_id = ElementMaker().make_element(
element_name="capsfilter", node=node, username=username)
rtp_capsfilter.set_property("caps", Gst.Caps.from_string(
"application/x-rtp,media=(string)video,encoding-name=(string)H264,payload=(int)96,"
"clock-rate=(int)90000,rtcp-fb-nack=(boolean)true,rtcp-fb-nack-pli=(boolean)true,"
"rtcp-fb-ccm-fir=(boolean)true,rtcp-fb-transport-cc=(boolean)true"))
elements.append(rtp_capsfilter)
# -----------------------------------------------------------------------------
# webrtcbin
# -----------------------------------------------------------------------------
webrtcbin, unique_id = ElementMaker().make_element(
element_name="webrtcbin", node=node, username=username)
if not webrtcbin:
sys.stderr.write(" Unable to create webrtcbin \n")
webrtcbin.set_property("bundle-policy", "max-bundle")
webrtcbin.set_property(
"turn-server",
f"hidden")
elements.append(webrtcbin)
this is both ice and offer
def on_negotiation_needed(self, element,is_h264):
outputUserInfoMessage(f"choosing negotiation based on is_h264 which is {is_h264}")
promise = Gst.Promise.new_with_change_func(self.on_h264_offer_created, element, None)
element.emit('create-offer', None, promise)
def send_ice_candidate_message(self, _, mlineindex, candidate):
icemsg = json.dumps({'ice': {'candidate': candidate, 'sdpMLineIndex': mlineindex}})
# چک کن کانکشن هنوز باز هست
if self.conn is None or self.conn.closed:
outputUserErrorMessage(
f"Cannot send ICE: connection is closed",
user=self.user_name
)
return # ← به جای crash، gracefully رد کن
loop = asyncio.new_event_loop()
try:
outputUserInfoMessage(f"sending ice: {icemsg}", user=self.user_name)
loop.run_until_complete(self.conn.send(icemsg))
except Exception as e:
outputUserErrorMessage(f"Failed to send ICE candidate: {e}", user=self.user_name)
finally:
loop.close()
def on_h264_offer_created(self, promise, _, __):
promise.wait()
reply = promise.get_reply()
offer = reply['offer']
sdp = offer.sdp.as_text()
def fix_h264_fmtp(sdp_text):
import re
h264_pts = set()
lines = sdp_text.splitlines()
for line in lines:
m = re.match(r'a=rtpmap:(\d+)\s+H264/90000', line, re.IGNORECASE)
if m:
h264_pts.add(m.group(1))
out = []
for line in lines:
m = re.match(r'a=fmtp:(\d+)\s+(.*)$', line)
if m and m.group(1) in h264_pts:
params = {}
for p in m.group(2).split(';'):
p = p.strip()
if '=' in p:
k, v = p.split('=', 1) # first '=' only
params[k.strip()] = v.strip()
# DO NOT overwrite profile-level-id. rtph264pay derives it from the
# actual SPS. Verified on GStreamer 1.24 with the config above, it
# emits 42c028 — hardcoding 42e028 would advertise a stream that
# differs from what is really being sent.
# Only supply a fallback if the payloader gave us nothing.
params.setdefault('profile-level-id', '42c028')
params.setdefault('packetization-mode', '1')
params['level-asymmetry-allowed'] = '1'
line = f"a=fmtp:{m.group(1)} " + ';'.join(
f"{k}={v}" for k, v in params.items())
out.append(line)
return '\r\n'.join(out) + '\r\n'
sdp = fix_h264_fmtp(sdp)
# Parse SDP to GstSdp.SDPMessage
result, sdpmsg = GstSdp.SDPMessage.new()
GstSdp.sdp_message_parse_buffer(sdp.encode(), sdpmsg)
# Create modified WebRTCSessionDescription
modified_offer = GstWebRTC.WebRTCSessionDescription.new(offer.type, sdpmsg)
promise = Gst.Promise.new()
self.webrtc.emit('set-local-description', modified_offer, promise)
self.send_sdp_offer(modified_offer)