Delay in VideoCapture because of buffer

Hello.
I tried to use VideoCapture and get video from several streams, but my computer can’t read frames from stream faser than stream put them into buffer.
Because of this buffer accumulates more and more frames.
Methods read() or grab() takes from buffer the first frame, not last. It makes delay of image.
How to solve this problem?
python 3.7.2, opencv 4.5.2

My tries:

  1. Make buffer short
    I thought that if i make buffer shorter, it should accumulate less frames and make delay shorter. But setting CAP_PROP_BUFFERSIZE was deleted from method after version 4.0. Or i dont know how to use it… (but set() didnt change nothong)

  2. Get last frame
    In new version i found it:
    CAP_PROP_XI_RECENT_FRAME
    Python: cv.CAP_PROP_XI_RECENT_FRAME
    GetImage returns most recent frame.
    But if i use method set(cv2.CAP_PROP_XI_RECENT_FRAME,…) it doesnt change nothing.
    Method “get(cv2.CAP_PROP_XI_RECENT_FRAME)” always returns 0.0.
    How to use it??? Is it working?

  3. Get images (not streams) from camera or always reconnect with cap=cv2.VideoCapture("…") to remake a buffer
    It overload the port and make it to became disable

  4. Always get frames from buffer for keeping it clear (Stupid try, but maybe it helps)


import cv2
import threading
from threading import Lock

class Camera:
    last_frame = None
    last_ready = None
    lock = Lock()
    capture=None

    def __init__(self, rtsp_link):
        self.capture = cv2.VideoCapture(rtsp_link)
        thread = threading.Thread(target=self.rtsp_cam_buffer, args=(), name="rtsp_read_thread")
        thread.daemon = True
        thread.start()

    def rtsp_cam_buffer(self):
        while True:
            with self.lock:
                self.last_ready = self.capture.grab()

    def getFrame(self):
        if (self.last_ready is not None):
            self.last_ready,self.last_frame=self.capture.retrieve()
            return self.last_frame.copy()
        else:
            return -1

It make delay shorter (not 5-10 seconds but 1-1.5), but delay is still unstable and unsinchronise cameras (sometimes one is faster then other). I want make it WITHOUT DELAY.

Sorry if i had mistakes, but it is not my native language.

Help me, please :frowning:

those are only for Ximea, not for v4l or such

Oh. I got it. Thanks.
I found that:
https://docs.opencv.org/3.4/d4/d15/group__videoio__flags__base.html#gaeb8dd9c89c10a5c63c139bf7c4f5704d
I missed it before. I think, it is all that i need.

Edit: It’s not. I found cv2.CAP_PROP_POS_FRAMES that can return number of next frame and i can also use it to set number of next frame. BUT. I have no idea, how can i got number of last frame (or stack length) to set next frame on it.

it’s always the same solution

  • spawn a thread
  • thread reads frames
  • thread keeps latest frame around
  • other code uses latest frame (or waits for an update)

This news sound sad :frowning:
And its no chance to make it without cratch?

“cratch”?
what do you mean?

Oh, my mistake. Crutch. But if it also told you nothing, it is like repearing of hole in the boat with adhesive tape. It works, but not so beautiful and useful.
“Костыль”

I’m also looking for “last frame problem” solution. And I also think that reading all frames isn’t good idea. What about changing opencv source and try to implement possibility to get just last frame from the videocapture object? Is there a way to recompile library for Python? Did anyone try to do that?

For example, file “cap.cpp” contains implementation for
bool VideoCapture::read(OutputArray image)
it seems to be possible to make some tweaks to this method to get exact latest frame from capture buffer. But how to compile it for further usage in projects?

Internally VideoCapture() would still have to read and decode the whole bitstream so I cannot see why “reading all frames isn’t a good idea”. On the other hand having a utility routine which only returns the last frame may be of use to some.

well, I think I got why VideoCapture()have to read whole bitstream. This is because of streaming service doesn’t send video frames as they are. A stream contains one keyframe followed by changes to it, but not frames like jpeg pictures. That is why VideoCapture() HAVE to process all the changes to key frame to get last frame as it is. Am I right?

Pretty much yes. It is slightly more complex but the conclusion is still the same, the whole bit stream needs to be read, if any of it is missed you will get corruptions.