Skip to content

Commit

Permalink
Fix fundamental floating point error in Clip.iter_frames (#1195)
Browse files Browse the repository at this point in the history
  • Loading branch information
tburrows13 authored May 22, 2020
1 parent b2ed1f6 commit ab5eb5e
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `IndexError` in `vfx.freeze`, `vfx.time_mirror` and `vfx.time_symmetrize` [#1124]
- Using `rotate()` with a `ColorClip` no longer crashes [#1139]
- `AudioFileClip` would not generate audio identical to the original file [#1108]
- Several issues resulting from incorrect time values due to floating point errors [#1195], for example:
- Blank frames at the end of clips [#210]
- Sometimes getting `IndexError: list index out of range` when using `concatenate_videoclips` [#646]


## [v1.0.3](https://github.com/zulko/moviepy/tree/v1.0.3) (2020-05-07)
Expand Down
6 changes: 5 additions & 1 deletion moviepy/Clip.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,11 @@ def iter_frames(self, fps=None, with_times=False, logger=None, dtype=None):
for frame in myclip.iter_frames()])
"""
logger = proglog.default_bar_logger(logger)
for t in logger.iter_bar(t=np.arange(0, self.duration, 1.0 / fps)):
for frame_index in logger.iter_bar(t=np.arange(0, int(self.duration * fps))):
# int is used to ensure that floating point errors are rounded
# down to the nearest integer
t = frame_index / fps

frame = self.get_frame(t)
if (dtype is not None) and (frame.dtype != dtype):
frame = frame.astype(dtype)
Expand Down
23 changes: 23 additions & 0 deletions tests/test_compositing.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,26 @@ def test_clips_array_duration():
video = clips_array([[red, green, blue]]).set_duration(5)
video.write_videofile(join(TMP_DIR, "test_clips_array.mp4"))
close_all_clips(locals())


def test_concatenate_self():
clip = BitmapClip([["AAA", "BBB"], ["CCC", "DDD"]]).set_fps(1)
target = BitmapClip([["AAA", "BBB"], ["CCC", "DDD"]]).set_fps(1)

concatenated = concatenate_videoclips([clip])

concatenated.write_videofile(join(TMP_DIR, "test_concatenate_self.mp4"))
assert concatenated == target


def test_concatenate_floating_point():
"""
>>> print("{0:.20f}".format(1.12))
1.12000000000000010658
This test uses duration=1.12 to check that it still works when the clip duration is
represented as being bigger than it actually is. Fixed in #1195.
"""
clip = ColorClip([100, 50], color=[255, 128, 64], duration=1.12).set_fps(25.0)
concat = concatenate_videoclips([clip])
concat.write_videofile("concat.mp4", preset="ultrafast")

0 comments on commit ab5eb5e

Please sign in to comment.