OpenCV's VideoCapture is broken and hasn't been fixed for the last 5 years: opencv/opencv#9053
This is a PyAV based replacement. Unlike other implementations it can seek at any time.
How to use:
reader = VideoReader('video.mp4')
reader.seek(reader.total_frames - 100) # frame number
while True:
frame = reader.read()
if not frame:
break
# frame is an ndarray - do something with it
print(f'frame {reader.position}: {frame}')
reader.close()
This class was quite useful for me. However, I think I found some bugs.
seek() reads the requested frame from the stream and does not add this frame to the output of read(). In fact, when opening a file, the first frame is skipped with the call to self.seek(0).
One solution is to prepend the last read frame to self.iter, so the next call to read() provides the correct frame:
Other problem I found was with discarding the packets with dts set as None. In some videos I tested, the last frame was discarded. This is, the last packet had the dts set to None but also contained the last frame of the stream. I changed iter_frames() to avoid discarding any frame: