低延迟地从 IP 摄像机获取帧

2023-12-01

我当前正在使用此命令从 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 命令相同(或更好)的结果。

我已经参考了:如何将原始 RTSP 流转储到文件?, 打开CV RTSP相机缓冲滞后, 如何使用 python 通过管道传输 ffmpeg 的输出?, 与 ffplay 和 VLC 相比,ffmpeg 性能较差, 如何使用 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我现在使用的命令延迟时间小于 1 秒。

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.>

我做了一些关于减少视频延迟的研究。
My 以下答案表明相关的 FFmpeg 标志是-probesize 32 and -flags low_delay.

上述标志与视频相关decoder侧(接收侧)。

视频编码参数“发送器/编码器侧”对于确定端到端延迟更为重要。
添加参数-tune zerolatency将编码器延迟降至最低,但所需的带宽要高得多(并且可能与通过互联网进行流式传输无关)。
我将限制我对解码延迟的回答,因为它似乎与您的问题主题更相关。

关于“知道其他人如何以低延迟获取视频帧”的主题是一个单独问题的主题(我不知道答案)。


为了比较 FFplay 和 FFmpeg(解码器)之间的延迟差异,我创建了一个“自包含”测试示例。

主要“原则”:

  • 执行 FFmpeg 子进程以并行传输两个 RTSP 输出流。
    流式视频是合成模式,帧计数器作为视频上的文本。
    两个输出流应用相同的编码参数(仅端口不同)。
    RTSP IP 地址是127.0.0.1(本地主机)。
    (注:我们可能会使用三通复用器而不是编码两次,但我从未尝试过)。
  • 执行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:

Sample output (left side is OpenCV and right side is FFplay):
enter image description here

看起来 FFmpeg-OpenCV 延迟降低了6 frames添加之前-vf setpts=0到 FFplay 命令。

注意:我花了一些时间才找到解决方案,我决定保留原始帖子的结果,以显示添加setpts filter.


Update:

Adding -vf setpts=0解决了延迟问题。

最新答案来自以下帖子建议添加setpts将所有视频时间戳重置为零的视频过滤器。
对于音频流的存在来说,这可能不是一个好主意,但是当需要最低的视频延迟时,这是我能找到的最佳解决方案。

添加后-vf setpts=0FFplay 和 OpenCV 的延迟大致相同:

enter image description here


重复测试mpv媒体播放器:

(注:在我找到 FFplay 解决方案之前,它似乎更相关)。

当应用所有 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()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

低延迟地从 IP 摄像机获取帧 的相关文章

随机推荐

  • “使用操作码 153;此模拟器仅支持最多 152”

    我是二郎和牛仔的新手 我正在尝试一个非常简单的例子https ninenines eu docs en cowboy 2 0 guide getting started 但我已经陷入困境了 完成 make run 后我得到 mess ser
  • 从破折号的下拉列表中过滤行后显示数据表

    我是达世币新手 我想制作一个应用程序 我可以在其中从下拉过滤器中选择值 过滤数据集并显示数据表 我正在使用 dash table 我的示例应用程序代码如下 没有显示数据表 有谁知道我做错了什么 如何在仪表板应用程序中渲染仪表板 import
  • 片段中的选项卡视图

    我一直在尝试在片段内使用选项卡视图 但是通过导航栏访问它时出现了一些错误 第一次访问它时 我可以自由地从选项卡移动到选项卡 但是当再次访问此页面时从另一个片段 选项卡不再移动 我只卡在单个选项卡中 默认情况下仅显示第一个选项卡 请帮忙 这是
  • R 中截距回归模型的 abline 线不正确

    给出了可重现的示例 在下面 我得到一条 y 截距约为 30 的 abline 线 但回归表明 y 截距应该是 37 2851 我哪里错了 mtcars mpg 21 0 21 0 22 8 21 4 32 obs mtcars wt 2 6
  • 如何将参数从一个 Perl 脚本传递到另一个?

    我有一个运行的脚本 运行后它有一些信息需要传递给下一个要运行的脚本 Unix DOS 命令如下 perl x s param send pl perl x s param receive pl param send pl 是 Send pa
  • Java 9:什么是集合工厂方法? [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 Java 9 的到来为 Java 的 Collections API 带来了许多新功能 其中之一就是集合工厂方法 它们是什么以及我如何正确实施它们 Note 1 To preve
  • 仅使用C语言的分布式系统设计

    我的工作是实现一个分布式节点系统 如 p2p 节点 每个节点 比如 A B C 和 D 执行某些功能 并且需要彼此交互以进行各种操作 例如同步操作和其他操作例如 15 个 A 节点与一组 5 个 B 节点交互 进入负载最少的节点队列并获取令
  • 检测图像中的字体

    我有一个非常奇怪的要求 即应该检测 JPG 图像中文本的字体 如何做呢 我想知道有什么办法可以做到这一点 提前致谢 您可以尝试这些服务 什么字体我认为这是识别图像中字体的最准确的服务 不是完全自动化的并且有限制 它只会匹配 MyFonts
  • 如何在 GitHub 上进行快进合并?

    因此 我的一位同事尝试使用 GitHub 的 Web 界面中的 通过快进合并 选项来合并分支 以保持历史记录免受虚假合并提交的影响 master自要合并的功能分支启动以来 它们合并到的分支尚未取得进展 有趣的是 这并没有按预期工作 所有提交
  • 为什么我不能将 C# 方法声明为虚拟方法和静态方法?

    我有一个辅助类 它只是一堆静态方法 并且想对辅助类进行子类化 有些行为是唯一的 具体取决于子类 因此我想从基类调用虚拟方法 但由于所有方法都是静态的 我无法创建普通的虚拟方法 需要对象引用才能访问虚拟方法 有没有办法解决 我想我可以使用单例
  • 从 JsRender 中的嵌套块访问父变量

    我怎样才能访问props s key来自嵌套的for props object items key for prop other items key here I want to print the key from props 我试过了
  • 配置 Eclipse 以在工作区外部添加 buildpath 文件夹

    我正在 Mac 上开发 PHP 根据其他建议 我已将工作区设置在 MAMP 的 HTDOCS 文件夹中 不幸的是 这意味着我不能像在生产中那样使用 的链接 有什么建议么 相关地 工作区似乎阻止引用工作区外部的构建路径 但我想将敏感文件保留在
  • jQuery:我可以自动将插件应用到动态添加的元素吗?

    我正在将我的 Web 应用程序转换为完全 AJAX 架构 我有一个最初加载的母版页和一个加载动态内容的 div 容器 我创建了一些 jQuery 插件 将它们应用于某些元素以扩展它们的功能 我通常会在每个页面加载期间按如下方式调用这些函数
  • 如何通过匹配 BeautifulSoup 中元素属性中的文本来获取元素

    我有这个代码 a title Next Page Results 1 to 60 href class smallfont gt a 我想抓住a元素并获取 href 我怎样才能匹配title属性与Next Page 我想部分匹配标题属性中的
  • 限制 Git 分支访问的方法?

    我的 git 存储库中有四个分支 使用 GitHub 进行管理 生产 Staging Master 人名 发展 有没有办法限制对单个分支 人名 开发 的写访问 我该怎么做 类似问题 供参考 如何编写 git hook 来限制写入分支 使用
  • 哪个 Django 表单字段可以为我提供 的 HTML 输出?

    我有一个带有此输入的 html 表单
  • 开发模式下的GWT + JSTL——可能吗?

    我有一个 GWT 应用程序 由 roo 生成 我决定使用 Spring Security 来保护它 Roo 生成一个 login jspx 页面作为安全设置的一部分 并且此 jspx 使用一些基本的 JSTL 标记库 当在开发模式下运行时
  • 包含标头时防止出现多个 #define

    来自 python 我对正确的方法有点困惑 我正在尝试将该库包含在我的项目中 https github com nothings stb blob master stb image h 为此 我必须在导入文件之前 define STB IM
  • 如何在 JPA2 中强制使用 @ManyToOne 字段?

    我正在为应用程序设计持久性存储库 我是新来的休眠 JPA2我遇到了麻烦创造更复杂的关系在这种情况下外部强制键 一个例子 只是在记事本上写的 所以不完全是这样 我有一个名为 Person 的顶级类 它可以担任多个职位 另一个类 如果我像这样映
  • 低延迟地从 IP 摄像机获取帧

    我当前正在使用此命令从 RTSP 流获取帧并从标准输出读取帧 ffmpeg nostdin rtsp transport tcp i