I use the library PyAV because it's one of the fatest available with Python.
Here is a simple example of code I would like to use:
import av
video = av.open("My_Super_Video.mp4")
total_frames = # ????
for i, frame in enumerate(video.decode(video=0)):
img = frame.to_image() # PIL image
print("Frame: %d/%d ..." % (i, total_frames))
I could obviously use other libraries to load the library, however I would prefer using PyAV if possible due to its processing speed.
Question 1: Is it possible to obtain the number of frames with PyAV ? If yes, how ?
Question 2: In the case, I would consider using another library to load and process the video frame by frame. Which library would allow me to do the above with the highest speed as possible. I know the followings, but don't know how they compare:
Old question, but only partly answered. Let me answer the second question as well.
Question 1: Is it possible to obtain the number of frames with PyAV ? If yes, how ?
import av
with av.open("My_Super_Video.mp4") as container:
total_frames = container.streams.video[0].frames
Question 2: In the case, I would consider using another library to load and process the video frame by frame. Which library would allow me to do the above with the highest speed as possible. I know the followings, but don't know how they compare: [...]
ImageIO timings: 0.497
PyAV timings: 0.908
MoviePy timings: 0.766
OpenCV timings: 0.766
OpenCV timings: 0.569 (no conversion to RGB)
ImageIO is the fastest; hands down. OpenCV comes close (14% slower), but only if you can do your processing in BGR. If you have to work in RGB then the conversion costs you dearly (54% slower 🥵).
That said, it is highly workload-dependent and you should always benchmark with your specific setup. In practice, the difference is often negligible compared to how much time you spend processing each frame.
Here is the benchmark code for those interested:
import cv2
import av
import imageio.v3 as iio
from moviepy.editor import VideoFileClip
from PIL import Image
from timeit import Timer
# create a test video (roughly 11 sec and sane encoding)
frames = iio.imread("imageio:cockatoo.mp4", plugin="pyav")
iio.imwrite("test_video.mp4", frames, plugin="pyav", codec="h264")
def iio_read():
total_frames = iio.improps("test_video.mp4", plugin="pyav").shape[0]
for idx, frame in enumerate(iio.imiter("test_video.mp4", plugin="pyav")):
foo = Image.fromarray(frame)
# Note: I will not print in the benchmark. This will skew the result
# print("Frame: %d/%d ..." % (idx, total_frames))
def av_read():
with av.open("test_video.mp4") as container:
total_frames = container.streams.video[0].frames
for frame in container.decode(video=0):
foo = frame.to_image()
def moviepy_read():
# Can not read frame_count
for frame in VideoFileClip("test_video.mp4").iter_frames():
foo = Image.fromarray(frame)
def cv2_read():
cap = cv2.VideoCapture("test_video.mp4")
total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
success, frame = cap.read()
idx = 0
while success:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
foo = Image.fromarray(frame)
success, frame = cap.read()
idx += 1
def cv2_read2():
cap = cv2.VideoCapture("test_video.mp4")
total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
success, frame = cap.read()
idx = 0
while success:
foo = Image.fromarray(frame)
success, frame = cap.read()
idx += 1
repeats = 10
time_moviepy = min(Timer("moviepy_read()", globals=globals()).repeat(repeats, number=1))
time_cv2 = min(Timer("cv2_read()", globals=globals()).repeat(repeats, number=1))
time_cv2_no_convert = min(Timer("cv2_read2()", globals=globals()).repeat(repeats, number=1))
time_iio = min(Timer("iio_read()", globals=globals()).repeat(repeats, number=1))
time_av = min(Timer("av_read()", globals=globals()).repeat(repeats, number=1))
print(
f"""
ImageIO timings: {time_iio:.3f}
PyAV timings: {time_av:.3f}
MoviePy timings: {time_moviepy:.3f}
OpenCV timings: {time_cv2:.3f}
OpenCV timings: {time_cv2_no_convert:.3f} (no conversion to RGB)
"""
)
Package Versions:
av==10.0.0
moviepy==1.0.3
Pillow==9.4.0
opencv-python==4.7.0.68
imageio==2.25.0