【问题标题】:open h.264 video stream with gpu使用 gpu 打开 h.264 视频流
【发布时间】:2022-03-24 19:50:50
【问题描述】:

我使用 Opencv 在 Jetson Nano 上解码 h.264。

我使用此代码:

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

一切正常。 现在我不会尝试通过使用 GPU 解码来优化我的代码我的问题是我该怎么做? 我看到这个选项:

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)

但我的来源是 URL。

我很乐意为如何使用 GPU 从 python 中的 URL 解码 h.264 提供任何帮助。

    标签: python-3.x opencv gstreamer nvidia-jetson-nano


    【解决方案1】:

    我在我的计算机上使用 FFmpeg 命令来获取有关视频的信息,我得到了这个情节:

    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
    

    【讨论】:

    • 它可能只是原始 H264,不使用 rtp。用这个编辑了我的答案......
    • 最后,当我使用命令行时,它就可以工作了!但是当我使用 opencv 时,我得到:cap = <VideoCapture 0x7fa60e8a50> VideoCapture not opened
    • 很高兴看到一些改进!尝试将此作为源进行测试:gst-launch-1.0 videotestsrc ! nvvidconv ! nvv4l2h264enc insert-sps-pps=1 insert-vui=1 ! h264parse ! udpsink port=46002,在我的情况下,两个管道 cap = cv2.VideoCapture('udpsrc port=46002 ! h264parse ! avdec_h264 ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1', cv2.CAP_GSTREAMER)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) 都可以与 opencv 一起使用。
    • 我想我看到了问题,我的 Cuda 使用 OpenCV 4.5.0 编译,但在我的 pip 中,OpenCV 的版本是 4.5.5。奇怪的是我没有看到安装到版本 4.5.0,我在我的 python2 OpenCV 上看到版本 4.5.0 和 Cuda 编译有没有办法将构建移动到 Python 3 或者我必须重做 python3 的所有内容。
    • 您可以搜索这个,如果没有找到,请为此打开一个单独的主题。我还看到了 opencv python 无法同时为 python2 和 python3 安装的情况......我用来解决的奇怪方法是进入 python dist-packages 文件夹,将 cv2.so 重命名为 cv2.so.old 并将新的链接在那里使用ln -s <Your_new_build_python2_or_3_lib> cv2.so 构建python 版本,但几乎可以肯定有更干净的方法来解决这个问题;-P
    【解决方案2】:

    您将使用可以解码各种类型的 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'
    

    【讨论】:

    • 首先检查这是否仅适用于 gstreamer。从终端尝试: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。如果不工作(可能需要 10 秒来设置和运行),您将不得不检查多播地址(我没有使用基于单播前缀的地址 234.0.0.0 的经验)并确保没有防火墙阻止流。
    • 工作时,您可以使用 opencv 重试。还要确保 opencv 是使用 gstreamer 支持构建的。 opencv 提供了一个函数 getBuildInformation() 返回一个带有 opencv 配置的字符串,该字符串应该有一个带有“GSTREAMER_SUPPORT”的行,应该是“YES”。如果没有,您将不得不重建 opencv 以启用 gstreamer 支持。您可以使用github.com/AastaNV/JEP/tree/master/script 的脚本来构建和安装 opencv。
    • 感谢您的命令,我的 Gstreamer 使用 Open-Cv 启用。我从命令运行管道并收到此错误:警告:来自元素/GstPipeline:pipeline0/GstRtpJitterBuffer:rtpjitterbuffer0:无法解码流。附加调试信息:gstrtpjitterbuffer.c(3247):gst_rtp_jitter_buffer_chain ():/GstPipeline:pipeline0/GstRtpJitterBuffer:rtpjitterbuffer0:收到无效的 RTP 有效负载,正在丢弃。
    • 另外为什么管道不启动udpsrc uri=udp://234.0.0.0:46002?
    • 在 jetson 上模拟您的源:gst-launch-1.0 videotestsrc ! nvvidconv ! nvv4l2h264enc insert-sps-pps=1 insert-vui=1 ! h264parse ! rtph264pay ! udpsink port=5002 并在同一 jetson 上接收: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 工作正常(不过显示需要几秒钟)。你确定你的流是 H264 编码的吗?它是否使用与默认 96 不同的有效负载? RTP 流是否也有音频?
    猜你喜欢
    • 1970-01-01
    • 2013-09-22
    • 2016-12-02
    • 1970-01-01
    • 2015-06-14
    • 2015-12-19
    • 2011-05-20
    • 2016-03-23
    • 1970-01-01
    相关资源
    最近更新 更多