Skip to content

Commit

Permalink
Fix incohernet frame seek as describe in issue #2115 and pr #2117
Browse files Browse the repository at this point in the history
  • Loading branch information
osaajani committed Jan 30, 2025
1 parent 5541a1d commit 5b69eb5
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 5 deletions.
Binary file added media/smpte-2997.mp4
Binary file not shown.
26 changes: 21 additions & 5 deletions moviepy/video/io/ffmpeg_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ def initialize(self, start_time=0):
"""
self.close(delete_lastread=False) # if any

# self.pos represents the (0-indexed) index of the frame that is next in line
# to be read by self.read_frame().
# Eg when self.pos is 1, the 2nd frame will be read next.
self.pos = self.get_frame_number(start_time)

# Getting around a difference between ffmpeg and moviepy seeking:
# "moviepy seek" means "get the frame displayed at time t"
# Hence given a 29.97 FPS video, seeking to .01s means "get frame 0".
# "ffmpeg seek" means "skip all frames until you reach time t".
# This time, seeking to .01s means "get frame 1". Surprise!
#
# (In 30fps, timestamps like 2.0s, 3.5s will give the same frame output
# under both rules, for the timestamp can be represented exactly in
# decimal.)
#
# So we'll subtract an epsilon from the timestamp given to ffmpeg.
if self.pos != 0:
start_time = self.pos * (1 / self.fps) - 0.00001
else:
start_time = 0.0

if start_time != 0:
offset = min(1, start_time)
i_arg = [
Expand Down Expand Up @@ -143,11 +164,6 @@ def initialize(self, start_time=0):
}
)
self.proc = sp.Popen(cmd, **popen_params)

# self.pos represents the (0-indexed) index of the frame that is next in line
# to be read by self.read_frame().
# Eg when self.pos is 1, the 2nd frame will be read next.
self.pos = self.get_frame_number(start_time)
self.last_read = self.read_frame()

def skip_frames(self, n=1):
Expand Down
5 changes: 5 additions & 0 deletions tests/test_ffmpeg_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,5 +784,10 @@ def test_read_transparent_video():
assert mask[100, 100] == 255


def test_frame_seek():
reader = FFMPEG_VideoReader("media/smpte-2997.mp4", pixel_format="rgba")



if __name__ == "__main__":
pytest.main()

0 comments on commit 5b69eb5

Please sign in to comment.