I’ve compiled OpenCV 4.8.0 with Cuda 10.2, cudNN 7.6.5.32, Video_Codec_SDK_12.1.14, and am running it on Python 3.9.13. I’m trying to read specific frames from a video file (video.mkv) using OpenCV’s Cuda Video Reader, similar to how I would with the CPU-based VideoCapture.
Here’s how I would do it using VideoCapture:
cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)
For Cuda Video Reader, I currently have this code working:
video_reader = cv2.cudacodec.createVideoReader('video.mkv')
fps_received, fps = video_reader.get(cv2.CAP_PROP_FPS)
total_frames_received, total_frames = video_reader.get(cv2.CAP_PROP_FRAME_COUNT)
for second in range(1, int(total_frames // fps) + 1):
target_frame = int(second * fps)
# TODO: Read only the target_frame and skip the rest
I consulted the VideoReader API Reference and attempted to use the set() method, in which I can pass a VideoReaderPropertys. The only property that made sense to me was the PROP_DECODED_FRAME_IDX which is described as “Index for retrieving the decoded frame using retrieve().”
set_success = video_reader.setVideoReaderProps(propertyId=0, propertyVal=target_frame) #PROP_DECODED_FRAME_IDX
print(set_success) # This is always False
has_frame, frame = video_reader.nextFrame()
How can I read a specific frame in a video using the Cuda Video Reader?
Is there a property similar to CAP_PROP_POS_FRAMES for the Cuda version?
Currently the only way is to read the frames until you get to the desired position. Depending on your use case this can actually work quite effectively due to the speed of the decoder.
If/when
is merged you will be able to seek on initialization to a specific point.
Unfortunatley due to the mutlithreaded implementation of cudacodec::VideoReader it is difficult to allow on the fly frame seeking. For this to work effectively it would probably be better to have a single threaded version.