0

I try to get one frame from a remote RTSP source every 10 seconds so that I can get regular updates but avoid using too much CPU/bandwidth/IO resources. I am still figuring out how to do it. The most naive way should be running the following snippet every 10 seconds:

import cv2
import time

vcap = cv2.VideoCapture("rtsp://URL")
ret, frame = vcap.read()
if ret is True:
    cv2.imwrite('screenshot1.png',frame)
    print('done')
else:
    print('error')
vcap.release()

It works! But it opens and closes the RTSP instance each time, which appears to be a waste. Also, it will flood my authentication log with this automatic login. I try to make it better by doing the following:

import cv2
import time

vcap = cv2.VideoCapture("rtsp://URL")

while True:
    ret, frame = vcap.read()
    if ret is True:
        cv2.imwrite('screenshot2.png', frame)
        print('done')
    else:
        print('error')
    time.sleep(10)

The original idea is that, I keep the connection open but I only grab a frame every 10 seconds. The issue is, it doesn't work. My observation is that OpenCV will capture every frame from the resource, no matter if I call ret, frame = vcap.read(). OpenCV saves those frames in an internal buffet, even if I wait for 10 seconds before calling ret, frame = vcap.read() again, I still get the 2nd frame, not the expected 10 sec * 30 fps = 300th frame.

So my question is: is there a way that I can keep RTSP connection open but stop OpenCV from reading all the frames? (In my mind, I am thinking about something similar to a database connection--you can keep the connection without constantly doing SELECT)

PS: I am aware that if I control the RTSP source, I could turn its FPS parameter down from something like 30 to 1. As a result, the process becomes much less resource-intensive. This is in fact the trick I am using. But I am thinking if it can do better than this.

PPS1: I find this similar question: Screenshot every 5 or 10 min from rtsp source using ffmpeg . But it appears to be using the naive approach--it opens the connection, grab a frame and close it, regularly.

PPS2: I also find this similar question: Getting current frame with OpenCV VideoCapture in Python. But it appears to be using the 2nd approach--it grabs all frames and just discard those unneeded ones. While this approach works, it does not save any resources at all.

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
  • maybe you should read all frames without `sleep` and only use `time` to control when you write data. In stream you have to read frame by frame - you can't use some method to jump to other place in stream (like you could do in normal file) – furas May 29 '21 at 17:57
  • in some streams can be used compression which needs previous frame to create current frame so skiping frames may not work. – furas May 29 '21 at 18:21
  • You may use FFmpeg instead of OpenCV, as I posted [here](https://stackoverflow.com/questions/61023637/python-how-to-automatically-capture-image-from-rtsp-every-minute-up-until-24-ho). My posted solution is not working well, but I think I can fix it by adding `-vf fps=fps=1/10` as posted [here](https://superuser.com/questions/663928/ffmpeg-to-capture-stills-from-h-264-stream) and using a Python thread. Still... all the video frames are going to decoded (in a sub-process). – Rotem May 29 '21 at 20:48
  • @furas I guess you missed my point--what you said is what exactly I want to avoid. I try to minimize the bandwidth and CPU usage. If I do it your way, I am almost not saving anything. –  May 30 '21 at 03:25
  • @Rotem Yes that is the issue I want to solve. Since I have many many RTSP sources over a not-so-fast internet. I need to reduce the bandwidth consumption significantly to make the project work. –  May 30 '21 at 03:26
  • I want to say that maybe you can't avoid it. And only method is to reduce FPS from 30 to 1 - and this method you already know. – furas May 30 '21 at 09:56
  • @furas Yes it seems to me that this is the case...but without delving very deep into the source code of OpenCV or the protocol design of RTSP...I am not very sure about this conclusion. So I asked this question just to see if I can get a quick answer... –  May 30 '21 at 11:49
  • don't bother with OpenCV's source code. **no application** can do anything about it. this is how video streams work. you get _the stream_ the device produces. you can't just ask for frames whenever you like it, except to open and close the connection all the time. video streams aren't databases. -- your best option is to reduce the frame rate at the source, or to interpose a server that can handle the bandwidth and re-encoding cost, and do the reduction for your resource-starved end point. – Christoph Rackwitz Sep 03 '22 at 11:47

0 Answers0