如果由于 RTSP 摄像头问题导致执行停止,如何终止 cv2.VideoCapture(rtsp_url) 调用?

Posted

技术标签:

【中文标题】如果由于 RTSP 摄像头问题导致执行停止,如何终止 cv2.VideoCapture(rtsp_url) 调用?【英文标题】:How to terminate cv2.VideoCapture(rtsp_url) call if execution stalls due to RTSP camera issues? 【发布时间】:2021-10-08 05:05:03 【问题描述】:

我有总共 80 台摄像机的 RTSP URL。我正在尝试使用cv2.VideoCapture(rtsp_url) 从每个摄像头获取屏幕截图。我正在对每个相机捕获的屏幕截图进行一些图像处理操作。每台相机我总共有 80 个这样的 URL。示例 RTSP URL 是:

rtsp://192.168.0.101:554/user=admin_password=oyXv12aW_channel=1_stream=0.sdp?real_stream

现在,有时由于网络或其他技术问题,某些摄像头暂时无法正常工作。在这种情况下,cv2.VideoCapture(rtsp_url) 需要超过 30 秒才能返回。在正常情况下,通常需要 2-3 秒才能返回屏幕截图。但是,如果相机停机,则需要花费太多时间。由于我的应用程序在许多相机上的for 循环中运行,我不能等待。有时不活动的相机数量很高,并且执行循环需要很长时间。有什么办法可以减少cv2.VideoCapture的等待时间?

我还使用了multiprocessing,并尝试在进程超过给定时间阈值时终止进程。我不想使用multiprocessing,尽管它工作得很好。我想找到一个只使用opencv的解决方案

【问题讨论】:

我们可以添加一些如何添加等待时间的功能吗?如果时间到期,则函数调用应返回。有什么解决方法吗? 【参考方案1】:

多处理版本可能真的是你想要的

可以简化并行读取所有摄像头 可以处理各种与超时相关的问题

然而,一点阅读表明 OpenCV RTSP 处理是由 ffmpeg 在内部完成的,其行为部分由名为 OPENCV_FFMPEG_CAPTURE_OPTIONS 的环境变量控制

来自 ffmpeg 上的文档http://ffmpeg.org/ffmpeg-protocols.html#rtsp

timeout  
  Set socket TCP I/O timeout in microseconds.

我没有实用的方法来尝试这个,但也许你只需要在你的程序中设置它或先导出它

os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = "timeout;5000"
cam = cv2.VideoCapture("rtsp://YOUR_STREAMING_IP_ADDRESS:PORT/foo.sdp", cv2.CAP_FFMPEG)

见selected Answer to RTSP stream and OpenCV (Python)

【讨论】:

我之前尝试过这两种选择。这些都不起作用。 唉! ..如果您可以重现该效果,那么使用这些选项运行ffmpeg 是否有效?这将帮助您将其范围缩小到堆栈中出错的位置【参考方案2】:

由于您没有提供任何代码,我的假设是:当cv2.videoCapture 尝试检索帧但网络中断时,它会冻结 X 秒并停止您的程序,直到它超时或帧终于找回来了。我还假设您的整个程序在一个巨大的循环中运行,换句话说,您的程序同步运行并相互依赖。本质上,这个问题可以改写为:我们如何异步捕获 RTSP 相机帧?


这是一个经典的编程模型,我们可以使用threading 来处理繁重的 I/O 操作。您当前的情况是您有多个摄像头流,但如果任何一个摄像头出现故障,它就会停止整个应用程序。当相机无法正常工作时您的应用程序停止的原因是因为使用cv2.VideoCapture().read() 访问网络摄像头/流/相机是一个 阻塞操作,这意味着我们的主程序会停止,直到从缓冲区读取一帧并返回。解决方案很简单:我们可以通过将繁重的 I/O 操作减轻到单独的独立线程来使用线程来提高性能。这个想法是生成另一个线程来处理以 parallel 的方式轮询帧,而不是依赖以 sequential 顺序抓取帧的单个线程(我们的“主”线程) .通过使用这种方法,一旦根线程处理完一个帧,它只需要从 I/O 线程中抓取当前帧,而无需等待阻塞 I/O 操作。

这种方法的好处是,如果任何相机死机,它只会停止该特定 I/O 线程中的操作,而不会对主程序产生任何影响。使用这种方法,任何单个相机是否遇到技术问题都没有关系,因为所有阻塞 I/O 操作都在单个线程中,而不是在主应用程序的线程中。您还提到:

I don't want to use multiprocessing ... I want to find a solution using only OpenCV

您希望使用线程而不是多处理。不同的是线程共享相同的内存空间,而进程有自己独立的内存栈,不与主线程共享。这使得在具有多处理的进程之间共享对象变得有点困难。此外,由于cv2.videoCapture 是一个阻塞操作,我认为不可能有一个仅使用 OpenCV 的解决方案。话虽如此,我们的想法是为每个相机创建一个新线程,该线程除了轮询新帧之外什么都不做,而我们的主线程处理当前帧。您可以为每个 RTSP 流创建一个新的相机对象

from threading import Thread
import cv2, time

class VideoStreamWidget(object):
    def __init__(self, src=0):
        self.capture = cv2.VideoCapture(src)
        # Start the thread to read frames from the video stream
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        # Read the next frame from the stream in a different thread
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()
            time.sleep(.01)

    def show_frame(self):
        # Display frames in main program
        cv2.imshow('frame', self.frame)
        key = cv2.waitKey(1)
        if key == ord('q'):
            self.capture.release()
            cv2.destroyAllWindows()
            exit(1)

if __name__ == '__main__':
    video_stream_widget = VideoStreamWidget()
    while True:
        try:
            video_stream_widget.show_frame()
        except AttributeError:
            pass

有关处理多个摄像头流的实现,请查看capture multiple camera streams with OpenCV

对于来自 RTSP 摄像机的其他类似线程和流媒体

Python OpenCV streaming from camera OpenCV real time streaming video capture is slow. How to drop frames or get synced with real time? Video Streaming from IP Camera in Python Using OpenCV cv2.VideoCapture

【讨论】:

以上是关于如果由于 RTSP 摄像头问题导致执行停止,如何终止 cv2.VideoCapture(rtsp_url) 调用?的主要内容,如果未能解决你的问题,请参考以下文章

摄像头推流受前端请求而无故停止(中断):rtsp response send failed: Connection reset by peer(未解决)

监控rtsp交互失败怎么回事?

海康威视如何直接添加RTSP流?

如何获取网络摄像头(监控摄像头)的rtsp的地址流

如何将流式 rtsp 媒体嵌入到 html5 页面中

android 如何播放rtsp://110.80.31.70:6000/channe1