1

I decode h.264 on Jetson Nano using Open-cv.

I use this Code:

import cv2

try:
  cap = cv2.VideoCapture('udp://234.0.0.0:46002', cv2.CAP_FFMPEG)
  print(f"cap = {cap}")

except Exception as e:
       print(f"Error: {e}")

if not cap.isOpened():
    print('VideoCapture not opened')
    exit(-1)

while True:
    ret, frame = cap.read()
    # print(f"frame = {frame}")
    try:
      cv2.imshow('Image', frame)

    except Exception as e:
          print(e)
    if cv2.waitKey(1) & 0XFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

everything works fine. now I won't try to optimize my code by decoding using GPU my question is how can I do this? I see this option:

cap = cv2.VideoCapture('filesrc location=sample2.mp4 ! qtdemux ! queue ! h264parse ! omxh264dec ! nvvidconv ! video/x-raw,format=BGRx ! queue ! videoconvert ! queue ! video/x-raw, format=BGR ! appsink', cv2.CAP_GSTREAMER)

but my source is URL.

I would be happy to any help how to decode h.264 from URL in python using GPU.

2 Answers2

0

You would use uridecodebin that can decode various types of urls, containers, protocols and codecs.

With Jetson, the decoder selected by uridecodebin for h264 would be nvv4l2decoder, that doesn't use GPU but better dedicated HW decoder NVDEC.

nvv4l2decoder outputs into NVMM memory in NV12 format, while opencv appsink expects BGR format in system memory. So you would use HW converter nvvidconv for converting and copying into system memory. Unfortunately, nvvidconv doesn't support BGR format, so first convert into supported BGRx format with nvvidconv, and finally use CPU plugin videoconvert for BGRx -> BGR conversion such as:

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)

This is for the general way.

Though, for some streaming protocols it may not be so simple.

For RTP-H264/UDP, ffmpeg backend may only work with a SDP file. For gstreamer backend you would instead use a pipeline such as:

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'

As you can use FFMPEG, I'd speculate that received stream is using RTP-MP2T. So you would try:

# 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)

[Note that I'm not familiar with 234.0.0.0, so unsure if multicast-group should be used as I did].

If this doesn't work, you may try to get more information about received stream. You may try working ffmpeg such as:

ffmpeg  -hide_banner -loglevel debug -i udp://234.0.0.0:46002 -f xv display

If you see:

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

you may have to change clock-rate to 1200000 (default value is 90000):

application/x-rtp,media=video,encoding-name=MP2T,clock-rate=1200000

This is assuming the stream is mpeg2 ts. In this case, first lines show:

...
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 tries to guess and here found the stream was in mpegts format. You would check in your case what ffmpeg finds. Note that first guess may not be correct, you would have to check the whole log and see what it finds working.

Another speculation would be that your stream is not RTP, but rather raw h264 stream. In such case you may be able to decode with something like:

gst-launch-1.0 udpsrc port=46002 multicast-group=234.0.0.0 ! h264parse ! nvv4l2decoder ! autovideosink

If this works, for opencv you would use:

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'
SeB
  • 1,159
  • 6
  • 17
  • First check if this works from gstreamer only. From terminal, try: `gst-launch-1.0 udpsrc port=46002 multicast-group=234.0.0.0 ! application/x-rtp,encoding-name=H264 ! rtpjitterbuffer latency=500 ! rtph264depay ! h264parse ! nvv4l2decoder ! autovideosink`. If not working (may take 10s to setup and run), you would have to check for multicast address (I have no experience with unbicast prefix-based addresses 234.0.0.0) and be sure that no firewall blocks the stream. – SeB Mar 16 '22 at 20:17
  • When working you can retry with opencv. Be also sure that opencv is built with gstreamer support. opencv provides a function getBuildInformation() returning a string with opencv config, that should have a line with 'GSTREAMER_SUPPORT' that should be 'YES'. If not, you would have to rebuild opencv enabling gstreamer support. You may use the script at https://github.com/AastaNV/JEP/tree/master/script for building and installing opencv. – SeB Mar 16 '22 at 20:24
  • Thank you for the command, my Gstreamer enable with Open-Cv. I run the pipe line from command and I get this error: WARNING: from element /GstPipeline:pipeline0/GstRtpJitterBuffer:rtpjitterbuffer0: Could not decode stream. Additional debug info: gstrtpjitterbuffer.c(3247): gst_rtp_jitter_buffer_chain (): /GstPipeline:pipeline0/GstRtpJitterBuffer:rtpjitterbuffer0: Received invalid RTP payload, dropping. – Ariel Kantorovich Mar 17 '22 at 07:45
  • In addition why the pipeline not start udpsrc uri=udp://234.0.0.0:46002? – Ariel Kantorovich Mar 17 '22 at 14:59
  • Simulating your source on jetson with: `gst-launch-1.0 videotestsrc ! nvvidconv ! nvv4l2h264enc insert-sps-pps=1 insert-vui=1 ! h264parse ! rtph264pay ! udpsink port=5002` and receiving on same jetson with: `gst-launch-1.0 udpsrc uri=udp://224.1.1.1:5002 ! application/x-rtp,media=video,encoding-name=H264 ! rtpjitterbuffer latency=0 ! rtph264depay ! decodebin ! autovideosink` works fine (it takes a few seconds ro display, though). Are you sure your stream is H264 encoded ? Does it use a different payload than default 96 ? Does the RTP stream also have audio ? – SeB Mar 17 '22 at 23:09
  • Once again I want to say thank you for the response and patience. I did the example in the last comment and everything works fine. I'm sure the broadcast is on H264. As for the payload I admit I have no idea I think it is set to default. As for the RTP I think the file is without audio if that is it I'm not sure the video was sent in RTP I think it was sent in UDP. How am I supposed to proceed from here in your opinion Do you know the error message I get (which appears in my first response) – Ariel Kantorovich Mar 20 '22 at 07:28
  • Well, may be I've finally understood your case and edited my answer with new information. Sorry for not having understood at first. Hope this will work. – SeB Mar 20 '22 at 20:37
  • I try your new answers (2-options) and still get the error: WARNING: from element /GstPipeline:pipeline0/GstRtpJitterBuffer:rtpjitterbuffer0: Could not decode stream. Additional debug info: gstrtpjitterbuffer.c(3247): gst_rtp_jitter_buffer_chain (): /GstPipeline:pipeline0/GstRtpJitterBuffer:rtpjitterbuffer0: Received invalid RTP payload, dropping – Ariel Kantorovich Mar 21 '22 at 07:46
  • Probably the payload that I used (33) doesn't match your case. You may try other payloads such as 96. Re-edit my answer with additional tip. – SeB Mar 21 '22 at 12:27
  • I try make payload=96 and still not work in addition I use ffmpeg tip and this the output: Input #0, h264, from 'udp://234.0.0.0:46002': Duration: N/A, bitrate: N/A 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 – Ariel Kantorovich Mar 21 '22 at 13:46
  • ffmpeg says for your stream 1/1200000 while mine (using the command a few comments above) has 1/90000. I assume this is the clock rate. Never used such a high clock, don't know about any payload using this, but re-edited my answer for this. I'd suggest first not specifying payload (default is 96). – SeB Mar 21 '22 at 18:59
  • Thank you for your patience, still does not work I try to use fakesink to make debug for the pipeline. I get the warning error when I use rtpjitterbuffer maybe we can try another pipe. In addition, you use encoding-name=MP2T why not H264? – Ariel Kantorovich Mar 22 '22 at 07:38
  • [graph 0 input from stream 0:0 @ 0x558aae9d40] Setting video_size to value 720x576[graph 0 input from stream 0:0 @ 0x558aae9d40] Setting pix_fmt to value '0' Setting time_base to value 1/1200000 Setting 'pixel_aspect' to value '0/1' [graph 0 input from stream 0:0 @ 0x558aae9d40] Setting 'sws_param' to value 'flags=2' [graph 0 input from stream 0:0 @ 0x558aae9d40] Setting 'frame_rate' to value '25/1' w:720 h:576 pixfmt:yuv420p tb:1/1200000 fr:25/1 sar:0/1 sws_param:flags=2 [AVFilterGraph @ 0x558a9f7580] query_formats: 3 queried, 2 merged, 0 already done, 0 delayed – Ariel Kantorovich Mar 22 '22 at 07:43
  • I used MP2T because AFAIK (I'm using gstreamer 1.14.5) RTP-H264 would only run in ffmpeg backend with a sdp file. As you get it running, I supposed the stream was using RTP-MP2T than can embed H264 video. MP2T was just another speculation, though. Best way would be getting details from stream sender. – SeB Mar 23 '22 at 12:23
  • My udp stream is from pcap file. When I watch the data in wireshark I see only udp packets. Maybe you know some technique for extract information about the video from packets (maybe wireshark or another software) – Ariel Kantorovich Mar 23 '22 at 14:17
  • Hmm... I might not be able to guess for such case unless you give a public link to file and how you're using pcap for streaming so that I can reproduce your case. I've again edited my answer for adding some details...use ffmpeg that works with this stream and find the format. – SeB Mar 23 '22 at 19:47
  • I edit some answer with information from ffmpeg maybe It's can help – Ariel Kantorovich Mar 24 '22 at 07:39
0

I use the FFmpeg command on my computer to get information about the video and I get this plot:

ffmpeg  -hide_banner -loglevel debug -i udp://127.0.0.0:46002 -f xv display
Splitting the commandline.
Reading option '-hide_banner' ... matched as option 'hide_banner' (do not 
show program banner) with argument '1'.
Reading option '-loglevel' ... matched as option 'loglevel' (set logging 
level) with argument 'debug'.
Reading option '-i' ... matched as input url with argument 
'udp://127.0.0.0:46002'.
Reading option '-f' ... matched as option 'f' (force format) with argument 
'xv'.
Reading option 'display' ... matched as output url.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option hide_banner (do not show program banner) with argument 1.
Applying option loglevel (set logging level) with argument debug.
Successfully parsed a group of options.
Parsing a group of options: input url udp://127.0.0.0:46002.
Successfully parsed a group of options.
Opening an input file: udp://127.0.0.0:46002.
[NULL @ 0000020a7c5ded80] Opening 'udp://127.0.0.0:46002' for reading
[udp @ 0000020a7c5cb700] No default whitelist set
[udp @ 0000020a7c5cb700] end receive buffer size reported is 393216
[h264 @ 0000020a7c5ded80] Format h264 probed with size=32768 and score=51
[h264 @ 0000020a7c5ded80] Before avformat_find_stream_info() pos: 0 bytes 
read:33339 seeks:0 nb_streams:1
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[extract_extradata @ 0000020a7c60eec0] nal_unit_type: 1(Coded slice of a 
non-IDR picture), nal_ref_idc: 2
Last message repeated 1 times
[h264 @ 0000020a7c631340] nal_unit_type: 1(Coded slice of a non-IDR 
picture), nal_ref_idc: 2
Last message repeated 1 times
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[h264 @ 0000020a7c631340] decode_slice_header error
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[h264 @ 0000020a7c631340] decode_slice_header error
[h264 @ 0000020a7c631340] no frame!
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[extract_extradata @ 0000020a7c60eec0] nal_unit_type: 1(Coded slice of a 
non-IDR picture), nal_ref_idc: 2
Last message repeated 1 times
[h264 @ 0000020a7c631340] nal_unit_type: 1(Coded slice of a non-IDR 
picture), nal_ref_idc: 2
Last message repeated 1 times
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[h264 @ 0000020a7c631340] decode_slice_header error
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[h264 @ 0000020a7c631340] decode_slice_header error
[h264 @ 0000020a7c631340] no frame!
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[extract_extradata @ 0000020a7c60eec0] nal_unit_type: 1(Coded slice of a 
non-IDR picture), nal_ref_idc: 2
Last message repeated 1 times
[h264 @ 0000020a7c631340] nal_unit_type: 1(Coded slice of a non-IDR 
picture), nal_ref_idc: 2
Last message repeated 1 times
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[h264 @ 0000020a7c631340] decode_slice_header error
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[h264 @ 0000020a7c631340] decode_slice_header error
[h264 @ 0000020a7c631340] no frame!
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[extract_extradata @ 0000020a7c60eec0] nal_unit_type: 1(Coded slice of a 
non-IDR picture), nal_ref_idc: 2
Last message repeated 1 times
[h264 @ 0000020a7c631340] nal_unit_type: 1(Coded slice of a non-IDR 
picture), nal_ref_idc: 2
Last message repeated 1 times
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[h264 @ 0000020a7c631340] decode_slice_header error
[h264 @ 0000020a7c631340] non-existing PPS 0 referenced
[h264 @ 0000020a7c631340] decode_slice_header error
[h264 @ 0000020a7c631340] no frame!
[extract_extradata @ 0000020a7c60eec0] nal_unit_type: 7(SPS), nal_ref_idc:3
[extract_extradata @ 0000020a7c60eec0] nal_unit_type: 8(PPS), nal_ref_idc:3
[extract_extradata @ 0000020a7c60eec0] nal_unit_type: 5(IDR), nal_ref_idc:3
Last message repeated 1 times
[h264 @ 0000020a7c631340] nal_unit_type: 7(SPS), nal_ref_idc: 3
[h264 @ 0000020a7c631340] nal_unit_type: 8(PPS), nal_ref_idc: 3
[h264 @ 0000020a7c631340] nal_unit_type: 5(IDR), nal_ref_idc: 3
Last message repeated 1 times
[h264 @ 0000020a7c631340] Format yuv420p chosen by get_format().
[h264 @ 0000020a7c631340] Reinit context to 720x576, pix_fmt: yuv420p
[h264 @ 0000020a7c631340] nal_unit_type: 1(Coded slice of a non-IDR 
picture), nal_ref_idc: 2
Last message repeated 11 times
[h264 @ 0000020a7c5ded80] max_analyze_duration 5000000 reached at 5000000 
microseconds st:0
[h264 @ 0000020a7c5ded80] After avformat_find_stream_info() pos: 971047 
bytes read:971495 seeks:0 frames:128
Input #0, h264, from 'udp://127.0.0.0:46002':
Duration: N/A, bitrate: N/A
Stream #0:0, 128, 1/1200000: Video: h264 (Constrained Baseline), 1 
reference frame, yuv420p(progressive, left), 720x576, 0/1, 25 fps, 25 tbr, 
1200k tbn, 50 tbc
Successfully opened the file.
Parsing a group of options: output url display.
Applying option f (force format) with argument xv.
Successfully parsed a group of options.
Opening an output file: display.
[NULL @ 0000020a7ce73000] Requested output format 'xv' is not a suitable 
output format
display: Invalid argument
[AVIOContext @ 0000020a7c610300] Statistics: 971495 bytes read, 0 seeks
  • It may be just raw H264, not using rtp. Edited my answer with this... – SeB Mar 24 '22 at 11:52
  • finally when I use command line it's work! but when I use opencv I get : `cap = VideoCapture not opened` – Ariel Kantorovich Mar 24 '22 at 13:26
  • Nice to see some improvement ! Try testing with this as source: `gst-launch-1.0 videotestsrc ! nvvidconv ! nvv4l2h264enc insert-sps-pps=1 insert-vui=1 ! h264parse ! udpsink port=46002` and in my case both pipelines `cap = cv2.VideoCapture('udpsrc port=46002 ! h264parse ! avdec_h264 ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1', cv2.CAP_GSTREAMER)` and `cap = cv2.VideoCapture('udpsrc port=46002 ! h264parse ! nvv4l2decoder ! nvvidconv ! video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1', cv2.CAP_GSTREAMER)` do work with opencv. – SeB Mar 24 '22 at 18:39
  • I think I see the problem, my Cuda compiles with OpenCV 4.5.0 but in my pip, the version of OpenCV is 4.5.5. What's weird is that I'm not see install to version 4.5.0, I see on my python2 OpenCV with version 4.5.0 and Cuda compile Is there a way to move build to Python 3 or do I have to redo everything for python3. – Ariel Kantorovich Mar 27 '22 at 06:23
  • You may search for this and if not finding open a separate topic for this. I have also seen cases where opencv python failed to install for both python2 and python3... The weird way I used to solve was going into python dist-packages folder, rename cv2.so as cv2.so.old and link there the new build version of python with `ln -s cv2.so`, but almost sure there is a more clean way to fix this ;-P – SeB Mar 27 '22 at 19:17
  • The weirdest thing I see, When I am in the directory /usr/lib/python3.6/dist-packages/cv2/python3.6 and I use cv2.getBuildInformation() I get everything fine, The good part is that it's working and the pipeline is Ok :) but I need to run my python script from this path. how I can link the build? – Ariel Kantorovich Mar 28 '22 at 08:57