基于FFmpeg+rtsp读取摄像头实时图像
Posted hs977986979
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于FFmpeg+rtsp读取摄像头实时图像相关的知识,希望对你有一定的参考价值。
项目介绍:前端时间做了一个项目用qt 编写软件获取海康摄像头rtsp视频流,实现实时显示。当时采用的是VLC-Qt播放RTSP流这种方式(参考:基于libVLC的视频播放器之二:使用VLC-Qt播放RTSP流_草上爬的博客-CSDN博客_libvlc rtsp)。花了一段时间研究也做出来了,可是发现了一个无法解决的问题,即无法解决视频延迟的问题,差不多延迟1秒左右。后面果断
放弃了,采用FFmpeg+rtsp这种方式。最终发现还是这种方式效果最好,解决了延迟问题,至少肉眼看不出。下面对此项目做个大致介绍,文章最后附上项目开发相关资料。
提示:使用rtsp方式获取海康摄像头图像需要开启海康的onvif功能。
参考连接:海康威视摄像头:开启onvif协议_海康威视_珠海陈坚浩博客
开发介绍:
开发软件:qt5.14.2
构建:MinGW64 bit
ffmpeg版本:3.4-win64
软件截图:
海康摄像头:
现在网络摄像头很多都支持rtsp方式显示图像,通过这种方式一个软件可以显示很多厂家的摄像头,兼容性更强。
提供不同厂家摄像头的rtsp地址:
一、海康、中威摄像机
格式1:
主码流:rtsp://admin:12345@192.168.1.64:554/Streaming/Channels/1
子码流:rtsp://admin:12345@192.168.1.64:554/Streaming/Channels/2
第三码流:rtsp://admin:12345@192.168.1.64:554/Streaming/Channels/3
格式2:
rtsp://admin:12345@192.168.1.64:554/ch1/main/av_stream
二、大华
rtsp://admin:12345@192.168.1.64:554/cam/realmonitor?channel=1&subtype=0
三、英飞拓
球机:
单播和组播地址一致
高码流(主码流)RTSP地址:rtsp://admin:admin@192.168.1.64/1/1080p
低码流(子码流)RTSP地址:rtsp://admin:admin@192.168.1.64/1/D1
半球和枪机:(亭子、车道)
单播:
高码流(主码流)RTSP地址:rtsp://192.168.1.64:554/1/h264major
低码流(子码流)RTSP地址:rtsp://192.168.1.64:554/1/h264minor
组播:
高码流(主码流)RTSP地址:rtsp://192.168.1.64:554/1/h264major/multicast
低码流(子码流)RTSP地址:rtsp://192.168.1.64:554/1/h264minor/multicast
四、三星
单播:
高码流rtsp地址:
rtsp://admin:admin001@192.168.1.64:554/onvif/profile2/media.smp(720P)
低码率rtsp地址
rtsp://admin:admin001@192.168.1.64:554/onvif/profile3/media.smp
组播:
高码流rtsp地址:
rtsp://admin:admin001@192.168.1.64:554/onvif/multicast/profile2/media.smp (720p)
低码流rtsp地址:
rtsp://admin:admin001@192.168.1.64:554/onvif/multicast/profile3/media.smp
五、宇视:
rtsp://admin:admin@192.168.1.64/media/video1/multicast
六、LG
单播和组播地址一致
高码流(主码流)RTSP地址:rtsp://admin:admin@192.168.1.64:554/Master-0
低码流(子码流)RTSP地址:rtsp://admin:admin@1192.168.1.64:554/Slave-0
七、派尔高网络摄像机:
RTSP主码流地址为:rtsp://192.168.1.64/h264
第一从码流RTSP地址为:rtsp://192.168.1.64/h264_2
第二从码流RTSP地址为:rtsp://192.168.1.64/h264_3
八、安讯士网络摄像机:
单播:
rtsp://root:123456@192.168.1.64/axis-media/media.amp?videocodec=h264&resolution=1280x720&fps=25
组播:
rtsp://root:123456@192.168.1.64/onvif-media/media.amp?profile=profile_1_h264&streamtype=multicast
http://root:123456@192.168.1.64/axis-cgi/alwaysmulti.sdp?camera=1
九、非凡
rtsp://admin:12345@192.168.1.64:554/streaming/channels/101
十、金三立
rtsp://Admin:111111@192.168.1.64/stream/av0_0
以上是项目的大致介绍;提供开发资料如下链接地址:
链接:https://pan.baidu.com/s/1SqF-w86mNFtJyh24mGxYcA?pwd=ms3g
提取码:ms3g
无实时约束处理大量 rtsp 摄像头
【中文标题】无实时约束处理大量 rtsp 摄像头【英文标题】:Handle large number of rtsp cameras without real-time constraint 【发布时间】:2022-01-09 07:12:36 【问题描述】:问题定义
假设我有大量的rtsp相机(> 100),我想对其进行一些操作,例如图像特征提取。
重要:我对实时性能不感兴趣,我可以在一分钟内进行 4 次特征提取。显然,越多越好!
现在,瓶颈是图像采集。帧是用cv2
获取的
请阅读以下部分了解我的尝试。
伪代码(当前解决方案)
while True:
for every rstp_cameras:
open_connection
read_current_frame(no batch - the real time frame)
process_frame
close
我尝试过的
在 *** 上,您可以找到很多关于实时读取 rtsp 摄像头的答案,但都受到摄像头数量的限制或存在一些缺点。 我试过(用python):
-
每个相机的线程 [cv2 with ffmpeg]
为线程中的每个摄像头打开一个连接,然后获取每个摄像头可用的最后一帧。
此解决方案有效,但仅适用于少量摄像机。如果我们增加数字,高端 cpu 的使用率将达到 100%(因为线程在后台总是读取最后一帧,如果我不问最后一帧,则丢弃它)
[当前解决方案,无线程,ffmpeg with cv2] 在每次迭代时打开一个连接,读取帧并关闭连接。此解决方案使我可以使用最后一帧,但主要缺点是打开期间丢失了时间(打开所有帧丢失了大约 70 秒)
带有 gstreamer 的 Cv2,无线程
基于此answer。 如果您的摄像头数量很少,这是我发现的最佳解决方案。使用 20 台或更多相机时,线程解决方案也有同样的问题。
问题与回顾
现在,我很清楚,在一个工作站中处理所有这些摄像机是很困难的,因为我找到的所有解决方案都是为了返回可用的最后一帧(实时)连续读取背景。
目前,我还没有找到一个解决方案,可以让我打开一次连接,读取低 cpu 使用率的实时帧,这样我就可以在大量摄像头上使用它。
阅读的并行化是解决问题的唯一方法吗?我的意思是,将相机分成批次,在不同的工作站分配批次,然后以某种方式组合图像?
谢谢。
【问题讨论】:
是时候深入挖掘 ffmpeg 的 API 并直接使用它了。 OpenCV 具有用于视频 I/O 的方便接口。它们不是用来承受负载的。 【参考方案1】:您可以尝试使用带有-discard nokey
参数的FFmpeg,如here 所述。
我不确定它是否会起作用......
据我了解,-discard nokey
仅解码关键帧,并跳过所有其他视频帧。
假设只解码关键帧可以大大减少 CPU 使用率(取决于关键帧的频率)。
这是一个代码示例(针对一个 RTSP 流):
import numpy as np
import subprocess as sp
# Use public RTSP Streaming for testing:
in_stream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"
# Use OpenCV for getting the video resolution.
cap = cv2.VideoCapture(in_stream)
# Get resolution of input video
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Release VideoCapture - it was used just for getting video resolution
cap.release()
# http://zulko.github.io/blog/2013/09/27/read-and-write-video-frames-in-python-using-ffmpeg/
FFMPEG_BIN = "ffmpeg" # on Linux ans Mac OS (also works on Windows when ffmpeg.exe is in the path)
ffmpeg_cmd = [FFMPEG_BIN,
'-discard', 'nokey',
'-rtsp_transport', 'tcp',
'-max_delay', '30000000', # 30 seconds
'-i', in_stream,
'-f', 'rawvideo',
'-pix_fmt', 'bgr24',
'-vcodec', 'rawvideo', '-an', 'pipe:']
# Open sub-process that gets in_stream as input and uses stdout as an output PIPE.
process = sp.Popen(ffmpeg_cmd, stdout=sp.PIPE)
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).reshape((height, width, 3))
# Show frame for testing
cv2.imshow('frame', frame)
cv2.waitKey(1)
process.stdout.close()
process.wait()
cv2.destroyAllWindows()
如上尝试打开100个FFmpeg子进程...
【讨论】:
感谢您的回复!是的,它似乎对cpu的影响很小。但是,我做了这个实验,它不起作用。我创建了 100 个进程,遍历它们(在while True
内)并读取框架。在最后一次迭代中(即当我到达第 100 个相机时,我插入了一个time.sleep(8)
。然后,如果我观看我保存的图像,我可以看到它们没有反映现实,它们积累了很高的延迟,肯定大于8秒,好像被缓存了一样。这是个问题,我希望我看帧的时候能反映真实情况。
为避免堆积,为每个摄像头创建一个读取线程(排空管道)。仅在非常特殊的情况下,简单地迭代摄像机才会起作用,即所有视频流的 GOP 大小相同,并且您可以足够快地读取帧以避免累积。
我认为插入thread
来排空管道可能会使cpu 饱和,就像其他涉及线程的解决方案一样。
我认为线程不会使 CPU 饱和,因为执行 raw_frame = process.stdout.read(width*height*3)
不是 CPU 密集型的 - 在数据准备好之前,线程应该处于挂起状态。即使等待(内部 Python 实现)不是最有效的(并且存在上下文切换开销),它仍然是相对较轻的 CPU 任务。
好吧,我不明白你的意思。我会试试看。谢谢!以上是关于基于FFmpeg+rtsp读取摄像头实时图像的主要内容,如果未能解决你的问题,请参考以下文章
FFmpeg入门详解之124:Qt5 FFmpeg单路网络摄像头采集预览