This page explains how acvr interprets frame indices and how the different read modes trade off latency and precision, especially for variable-frame-rate (VFR) videos.
Index policies
acvr supports two ways to interpret an index i:
-
decode:
irefers to the decode-order frame number in the stream. This is exact and deterministic across reads. On constant-frame-rate (CFR) videos, decode-order aligns with the nominal timeline. On VFR videos, decode-order may differ from the nominal timeline. -
timeline:
iis mapped to a timestamp using the nominal frame rate (guessed_ratefrom PyAV when available). The reader then seeks accurately to the frame at/after that timestamp. This aligns better with the nominal timeline on VFR, but two assets with the same nominal rate might still differ due to encoder/gop structures.
You can choose the policy for array-style access via:
from acvr import VideoReader
# Use timeline indexing globally for [] access (e.g., reader[100])
reader = VideoReader(path, index_policy="timeline")
frame = reader[100] # mapped via nominal FPS to timestamp
Regardless of index_policy, you can always call mode-specific APIs.
Read modes
- accurate: index is decode-order, or pass
t_sto seek by timestamp. - accurate_timeline: index is mapped to timestamp via nominal FPS; then performs
the same accurate timestamp seeking as
accurate. - fast: approximate seek optimized for low latency; uses nominal timeline for good VFR alignment; exact on CFR for typical content.
- scrub: returns nearby keyframes; very fast and approximate; defaults to nearest keyframe and uses a small cache bucket for speed.
- sequential: decode in order using
read_nextor iteration; no seeking.
Recommendations
- For full sequential processing (e.g., feature extraction), prefer
read_nextorfor frame in reader, which uses the sequential decoder. - CFR or strict decode-order tasks: use
accurate(or defaultindex_policy='decode'). - VFR and UI preview: use
fastorscrub(nearest). For exact reads tied to nominal timeline, useaccurate_timeline. - If your project thinks in “timeline frames”, set
index_policy='timeline'on the reader to makereader[i]follow the nominal timeline.