您将使用可以解码各种类型的 url、容器、协议和编解码器的 uridecodebin。
使用 Jetson,uridecodebin 为 h264 选择的解码器将是 nvv4l2decoder,它不使用 GPU,但更好的专用硬件解码器 NVDEC。
nvv4l2decoder 以 NV12 格式输出到 NVMM 内存中,而 opencv appsink 期望系统内存中的 BGR 格式。因此,您将使用硬件转换器 nvvidconv 进行转换并复制到系统内存中。可惜nvvidconv不支持BGR格式,所以先用nvvidconv转换成支持的BGRx格式,最后用CPU插件videoconvert进行BGRx->BGR转换如:
pipeline='uridecodebin uri=rtsp://127.0.0.1:8554/test ! nvvidconv ! video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1'
cap = cv2.VideoCapture(pipeline, cv2.CAP_GSTREAMER)
这是一般的方式。
不过,对于某些流媒体协议,它可能并不那么简单。
对于 RTP-H264/UDP,ffmpeg 后端可能仅适用于 SDP 文件。
对于 gstreamer 后端,您将改为使用管道,例如:
pipeline='udpsrc port=46002 multicast-group=234.0.0.0 ! application/x-rtp,encoding-name=H264 ! rtpjitterbuffer latency=500 ! rtph264depay ! h264parse ! nvv4l2decoder ! nvvidconv ! video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1'
由于您可以使用 FFMPEG,我推测接收到的流使用的是 RTP-MP2T。所以你会尝试:
# Using NVDEC, but this may fail depending on sender side's codec:
cap = cv2.VideoCapture('udpsrc multicast-group=234.0.0.0 port=46002 ! application/x-rtp,media=video,encoding-name=MP2T,clock-rate=90000,payload=33 ! rtpjitterbuffer latency=300 ! rtpmp2tdepay ! tsdemux ! h264parse ! nvv4l2decoder ! nvvidconv ! video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1', cv2.CAP_GSTREAMER)
# Or using CPU (may not support high pixel rate with Nano):
cap = cv2.VideoCapture('udpsrc multicast-group=234.0.0.0 port=46002 ! application/x-rtp,media=video,encoding-name=MP2T,clock-rate=90000,payload=33 ! rtpjitterbuffer latency=300 ! rtpmp2tdepay ! tsdemux ! h264parse ! avdec_h264 ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1', cv2.CAP_GSTREAMER)
[请注意,我不熟悉 234.0.0.0,因此不确定是否应该像我一样使用多播组]。
如果这不起作用,您可以尝试获取有关接收流的更多信息。您可以尝试使用 ffmpeg,例如:
ffmpeg -hide_banner -loglevel debug -i udp://234.0.0.0:46002 -f xv display
如果你看到:
Stream #0:0, 133, 1/1200000: Video: h264 (Constrained Baseline), 1 reference frame, yuv420p(progressive, left), 720x576, 0/1, 25 fps, 25 tbr, 1200k tbn, 50 tbc
您可能需要将时钟速率更改为 1200000(默认值为 90000):
application/x-rtp,media=video,encoding-name=MP2T,clock-rate=1200000
这是假设流是 mpeg2 ts。在这种情况下,第一行显示:
...
Opening an input file: udp://127.0.0.1:5002.
[NULL @ 0x55761c4690] Opening 'udp://127.0.0.1:5002' for reading
[udp @ 0x55761a27c0] No default whitelist set
[udp @ 0x55761a27c0] end receive buffer size reported is 131072
[mpegts @ 0x55761c4690] Format mpegts probed with size=2048 and score=47
[mpegts @ 0x55761c4690] stream=0 stream_type=1b pid=41 prog_reg_desc=HDMV
[mpegts @ 0x55761c4690] Before avformat_find_stream_info() pos: 0 bytes read:26560 seeks:0 nb_streams:1
...
ffmpeg 尝试猜测,在这里发现流是 mpegts 格式。你会检查你的情况 ffmpeg 发现了什么。请注意,第一次猜测可能不正确,您必须检查整个日志并查看它发现什么有效。
另一种猜测是您的流不是 RTP,而是原始 h264 流。在这种情况下,您可以使用以下内容进行解码:
gst-launch-1.0 udpsrc port=46002 multicast-group=234.0.0.0 ! h264parse ! nvv4l2decoder ! autovideosink
如果这可行,对于 opencv,您将使用:
pipeline='udpsrc port=46002 multicast-group=234.0.0.0 ! h264parse ! nvv4l2decoder ! nvvidconv ! video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1'