gpt4 book ai didi

python - 以低延迟从 IP Camera 获取帧

转载 作者:行者123 更新时间:2023-12-04 22:46:23 40 4
gpt4 key购买 nike

我目前正在使用此命令从我的 RTSP 流中获取帧并从标准输出读取帧:

ffmpeg -nostdin -rtsp_transport tcp -i <rtsp_stream> -pix_fmt bgr24 -an -vcodec rawvideo -f rawvideo -
但是,我希望获得与通过 ffplay 看到时相同的延迟:
ffplay -fflags nobuffer -flags low_delay -tune zerolatency -framedrop -rtsp_transport tcp <rtsp_stream>
或者当我通过 VLC Media > Open Network Stream 播放它时:network_caching=300ms。
我想知道我的 ffmpeg 命令可以使用哪些其他参数来获得与 ffplay 命令相比等效(或更好)的结果。
我引用了: How to dump raw RTSP stream to file? , Open CV RTSP camera buffer lag , How to pipe output from ffmpeg using python? , bad ffmpeg performace compared to ffplay and VLC , How to minimize the delay in a live streaming with ffmpeg
我目前的实现:
FFMPEG_CMD = "ffmpeg -nostdin -rtsp_transport tcp -i <rtsp_stream> -pix_fmt bgr24 -an -vcodec rawvideo -f rawvideo -".split(" ")
WIDTH = 2560
HEIGHT = 1440

process = subprocess.Popen(FFMPEG_CMD, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)

while True:
raw_frame = process.stdout.read(WIDTH*HEIGHT*3)
frame = np.frombuffer(raw_frame, np.uint8)
frame = frame.reshape((HEIGHT, WIDTH, 3))

<do stuff with frame/ show frame etc.>
谢谢阅读。
ffmpeg我现在使用的命令延迟时间 < 1s。
ffmpeg -nostdin -flags low_delay -rtsp_transport tcp -i <rtsp_stream> -pix_fmt bgr24 -an -vcodec rawvideo -f rawvideo -

使用来自答案的建议实现:
import subprocess
import numpy as np

FFMPEG_CMD = "ffmpeg -nostdin -flags low_delay -rtsp_transport tcp -i <rtsp_stream> -pix_fmt bgr24 -an -vcodec rawvideo -f rawvideo -".split(" ")
WIDTH = 2560
HEIGHT = 1440

process = subprocess.Popen(FFMPEG_CMD, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)

raw_frame = np.empty((HEIGHT, WIDTH, 3), np.uint8)
frame_bytes = memoryview(raw_frame).cast("B")

while process.poll() is None:
process.stdout.readinto(frame_bytes)
frame = raw_frame.reshape((HEIGHT, WIDTH, 3))

<do stuff with frame/ show frame etc.>

最佳答案

我做了一些关于减少视频延迟的研究。
我的 following answer证明相关的 FFmpeg 标志是 -probesize 32-flags low_delay .
上述标志与视频 相关解码器 侧(接收方)。
视频编码参数“发送器/编码器端”对于确定端到端延迟更为重要。
添加参数 -tune zerolatency将编码器延迟降至最低,但所需的带宽要高得多(并且可能与互联网上的流媒体无关)。
我将把我的答案限制在解码延迟上,因为它似乎与您的问题主题更相关。
关于“知道其他人如何以低延迟获取视频帧”的主题是一个单独问题的主题(我不知道答案)。

为了比较 FFplay 和 FFmpeg(解码器)之间的延迟差异,我创建了一个“自包含”测试样本。
主要“原则”:

  • 执行 FFmpeg 子流程以并行传输两个 RTSP 输出流。
    流式视频是合成模式,帧计数器作为视频上的文本。
    两个输出流应用相同的编码参数(只有端口不同)。
    RTSP IP 地址是 127.0.0.1 (本地主机)。
    (注意:我们可能会使用 tee muxer 而不是两次编码,但我从未尝试过)。
  • 执行FFplay子流程,解码并显示一个视频流。
  • 执行 FFmpeg 子流程,解码其他视频流。
    OpenCV imshow用于显示视频。
  • 具有较大计数器的显示视频是具有较低延迟的视频。

  • 代码示例(更新):
    import cv2
    import numpy as np
    import subprocess as sp
    import shlex


    rtsp_stream0 = 'rtsp://127.0.0.1:21415/live.stream' # Use localhost for testing
    rtsp_stream1 = 'rtsp://127.0.0.1:31415/live.stream'
    width = 256 # Use low resolution (for testing).
    height = 144
    fps = 30

    # https://stackoverflow.com/questions/60462840/ffmpeg-delay-in-decoding-h264
    ffmpeg_cmd = shlex.split(f'ffmpeg -nostdin -probesize 32 -flags low_delay -fflags nobuffer -rtsp_flags listen -rtsp_transport tcp -stimeout 1000000 -an -i {rtsp_stream0} -pix_fmt bgr24 -an -vcodec rawvideo -f rawvideo pipe:')


    # FFplay command before updating the code (latency is still too high):
    # ffplay_cmd = shlex.split(f'ffplay -probesize 32 -analyzeduration 0 -sync ext -fflags nobuffer -flags low_delay -avioflags direct -rtsp_flags listen -strict experimental -framedrop -rtsp_transport tcp -listen_timeout 1000000 {rtsp_stream1}')

    # Updated FFplay command - adding "-vf setpts=0" (fixing the latency issue):
    # https://stackoverflow.com/questions/16658873/how-to-minimize-the-delay-in-a-live-streaming-with-ffmpeg
    ffplay_cmd = shlex.split(f'ffplay -probesize 32 -analyzeduration 0 -sync ext -fflags nobuffer -flags low_delay -avioflags direct -rtsp_flags listen -strict experimental -framedrop -vf setpts=0 -rtsp_transport tcp -listen_timeout 1000000 {rtsp_stream1}')

    # Execute FFplay to used as reference
    ffplay_process = sp.Popen(ffplay_cmd)

    # Open sub-process that gets in_stream as input and uses stdout as an output PIPE.
    process = sp.Popen(ffmpeg_cmd, stdout=sp.PIPE) #,stderr=sp.DEVNULL


    # The following FFmpeg sub-process stream RTSP video.
    # The video is synthetic video with frame counter (that counts every frame) at 30fps.
    # The arguments of the encoder are almost default arguments - not tuned for low latency.
    # drawtext filter with the n or frame_num function https://stackoverflow.com/questions/15364861/frame-number-overlay-with-ffmpeg
    rtsp_streaming_process = sp.Popen(shlex.split(f'ffmpeg -re -f lavfi -i testsrc=size={width}x{height}:rate={fps} '
    '-filter_complex "drawtext=fontfile=Arial.ttf: text=''%{frame_num}'': start_number=1: x=(w-tw)/2: y=h-(2*lh): fontcolor=black: fontsize=72: box=1: boxcolor=white: boxborderw=5",'
    'split[v0][v1] ' # Split the input into [v0] and [v1]
    '-vcodec libx264 -pix_fmt yuv420p -g 30 -rtsp_transport tcp -f rtsp -muxdelay 0.1 -bsf:v dump_extra '
    f'-map "[v0]" -an {rtsp_stream0} '
    '-vcodec libx264 -pix_fmt yuv420p -g 30 -rtsp_transport tcp -f rtsp -muxdelay 0.1 -bsf:v dump_extra '
    f'-map "[v1]" -an {rtsp_stream1}'))


    while True:
    raw_frame = process.stdout.read(width*height*3)

    if len(raw_frame) != (width*height*3):
    print('Error reading frame!!!') # Break the loop in case of an error (too few bytes were read).
    break

    # Transform the byte read into a numpy array, and reshape it to video frame dimensions
    frame = np.frombuffer(raw_frame, np.uint8)
    frame = frame.reshape((height, width, 3))

    # Show frame for testing
    cv2.imshow('frame', frame)
    key = cv2.waitKey(1)

    if key == 27:
    break

    process.stdout.close()
    process.wait()
    ffplay_process.kill()
    rtsp_streaming_process.kill()
    cv2.destroyAllWindows()

    添加前的示例输出添加 -vf setpts=0 :
    样本输出(左侧是 OpenCV,右侧是 FFplay):
    enter image description here
    看起来 FFmpeg-OpenCV 延迟要低 6帧添加前 -vf setpts=0到 FFplay 命令。
    注意:我花了一些时间找到解决方案,我决定保留原始帖子的结果以显示添加 setpts 的重要性筛选。

    更新:
    添加 -vf setpts=0解决了延迟问题。
    来自 following post 的最新答案建议添加 setpts将所有视频时间戳重置为零的视频过滤器。
    存在音频流可能不是一个好主意,但是当需要最低的视频延迟时,这是我能找到的最佳解决方案。
    添加后 -vf setpts=0 FFplay 和 OpenCV 的延迟差不多:
    enter image description here

    使用 mpv media player 重复测试:
    (注意:在我找到 FFplay 解决方案之前,它似乎更相关)。
    当应用来自 this page 的所有 mpv“延迟黑客”时,mpv和OpenCV的延迟差不多:
    enter image description here
    FFplay肯定有解决方案,但我找不到...

    代码示例(使用 mpv 而不是 FFplay):
    import cv2
    import numpy as np
    import subprocess as sp
    import shlex

    rtsp_stream0 = 'rtsp://127.0.0.1:21415/live.stream' # Use localhost for testing
    rtsp_stream1 = 'rtsp://127.0.0.1:31415/live.stream'
    width = 256 # Use low resolution (for testing).
    height = 144
    fps = 30

    # https://stackoverflow.com/questions/60462840/ffmpeg-delay-in-decoding-h264
    ffmpeg_cmd = shlex.split(f'ffmpeg -nostdin -probesize 32 -flags low_delay -fflags nobuffer -rtsp_flags listen -rtsp_transport tcp -stimeout 1000000 -an -i {rtsp_stream0} -pix_fmt bgr24 -an -vcodec rawvideo -f rawvideo pipe:')

    # https://stackoverflow.com/questions/16658873/how-to-minimize-the-delay-in-a-live-streaming-with-ffmpeg
    #ffplay_cmd = shlex.split(f'ffplay -probesize 32 -analyzeduration 0 -sync ext -fflags nobuffer -flags low_delay -avioflags direct -rtsp_flags listen -strict experimental -framedrop -rtsp_transport tcp -listen_timeout 1000000 {rtsp_stream1}')

    # https://github.com/mpv-player/mpv/issues/4213
    mpv_cmd = shlex.split(f'mpv --demuxer-lavf-o=rtsp_flags=listen --rtsp-transport=tcp --profile=low-latency --no-cache --untimed --no-demuxer-thread --vd-lavc-threads=1 {rtsp_stream1}')

    # Execute FFplay to used as reference
    #ffplay_process = sp.Popen(ffplay_cmd)

    # Execute mpv media player (as reference)
    mpv_process = sp.Popen(mpv_cmd)

    # Open sub-process that gets in_stream as input and uses stdout as an output PIPE.
    process = sp.Popen(ffmpeg_cmd, stdout=sp.PIPE) #,stderr=sp.DEVNULL


    # The following FFmpeg sub-process stream RTSP video.
    # The video is synthetic video with frame counter (that counts every frame) at 30fps.
    # The arguments of the encoder are almost default arguments - not tuned for low latency.
    # drawtext filter with the n or frame_num function https://stackoverflow.com/questions/15364861/frame-number-overlay-with-ffmpeg
    rtsp_streaming_process = sp.Popen(shlex.split(f'ffmpeg -re -f lavfi -i testsrc=size={width}x{height}:rate={fps} '
    '-filter_complex "drawtext=fontfile=Arial.ttf: text=''%{frame_num}'': start_number=1: x=(w-tw)/2: y=h-(2*lh): fontcolor=black: fontsize=72: box=1: boxcolor=white: boxborderw=5",'
    'split[v0][v1] ' # Split the input into [v0] and [v1]
    '-vcodec libx264 -pix_fmt yuv420p -g 30 -rtsp_transport tcp -f rtsp -muxdelay 0.1 -bsf:v dump_extra '
    f'-map "[v0]" -an {rtsp_stream0} '
    '-vcodec libx264 -pix_fmt yuv420p -g 30 -rtsp_transport tcp -f rtsp -muxdelay 0.1 -bsf:v dump_extra '
    f'-map "[v1]" -an {rtsp_stream1}'))


    while True:
    raw_frame = process.stdout.read(width*height*3)

    if len(raw_frame) != (width*height*3):
    print('Error reading frame!!!') # Break the loop in case of an error (too few bytes were read).
    break

    # Transform the byte read into a numpy array, and reshape it to video frame dimensions
    frame = np.frombuffer(raw_frame, np.uint8)
    frame = frame.reshape((height, width, 3))

    # Show frame for testing
    cv2.imshow('frame', frame)
    key = cv2.waitKey(1)

    if key == 27:
    break

    process.stdout.close()
    process.wait()
    #ffplay_process.kill()
    mpv_process.kill()
    rtsp_streaming_process.kill()
    cv2.destroyAllWindows()

    关于python - 以低延迟从 IP Camera 获取帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71746326/

    40 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com