Skip to content

Commit

Permalink
Correctly set movie duration for conversion (#818)
Browse files Browse the repository at this point in the history
* Finding correct duration for movie when converting a mpg movie.

* Adding testing for update to converting MPEG movie.

* PEP8
  • Loading branch information
kenkehoe committed Apr 5, 2024
1 parent b3bb31f commit 920d254
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 6 deletions.
1 change: 1 addition & 0 deletions act/tests/sample_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from arm_test_data import DATASETS

# Single files
EXAMPLE_MPEG = DATASETS.fetch('nsacamskyradmovieC1.a1.20240401.100300.mpg')
EXAMPLE_MET1 = DATASETS.fetch('sgpmetE13.b1.20190101.000000.cdf')
EXAMPLE_MET_SAIL = DATASETS.fetch('gucmetM1.b1.20230301.000000.cdf')
EXAMPLE_MET_CSV = DATASETS.fetch('sgpmetE13.b1.20210401.000000.csv')
Expand Down
36 changes: 30 additions & 6 deletions act/utils/io_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import types

try:
import moviepy.editor as moviepy_editor
import moviepy.video.io.ImageSequenceClip
from moviepy.video.io.VideoFileClip import VideoFileClip

MOVIEPY_AVAILABLE = True
except (ImportError, RuntimeError):
Expand Down Expand Up @@ -337,11 +337,35 @@ def generate_movie(images, write_filename=None, fps=10, **kwargs):
write_directory.mkdir(parents=True, exist_ok=True)

if IS_MOVIE:
with VideoFileClip(images) as clip:
# Not sure why but need to set the duration of the clip with subclip() to write
# the full file out.
clip = clip.subclip(t_start=clip.start, t_end=clip.end * clip.fps)
clip.write_videofile(str(write_filename), fps=fps, **kwargs)
with moviepy_editor.VideoFileClip(images) as clip:
# There can be an issue converting mpeg to other movie format because the
# duration parameter in the movie file is not set. So moviepy guesses and
# can get the duration wrong. This will find the correct duration (to 0.1 seconds)
# and set before writing.
if Path(images).suffix == '.mpg':
import numpy as np
import warnings

with warnings.catch_warnings():
warnings.filterwarnings('ignore', category=UserWarning)
frame = None
duration = 0.0 # Duration of movie in seconds
while True:
result = clip.get_frame(duration)
if frame is not None and np.all(frame == result):
break

duration += 0.1
frame = result

clip = clip.set_start(0)
clip = clip.set_duration(duration)
clip = clip.set_end(duration)
clip.write_videofile(str(write_filename), **kwargs)

else:
clip.write_videofile(str(write_filename), **kwargs)

else:
clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(images, fps=fps)
clip.write_videofile(str(write_filename), **kwargs)
Expand Down
8 changes: 8 additions & 0 deletions tests/utils/test_io_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,5 +275,13 @@ def test_generate_movie():
assert Path(result).name == write_filename
assert np.isclose(Path(result).stat().st_size, 173189, 1000)

# Test converting MPEG to mp4
write_filename = 'movie3.mp4'
mpeg_file = sample_files.EXAMPLE_MPEG
result = act.utils.generate_movie(mpeg_file, write_filename=write_filename)
files = list(Path().glob(write_filename))
assert len(files) == 1
assert np.isclose(files[0].stat().st_size, 1625298, rtol=100, atol=100)

finally:
chdir(cwd)

0 comments on commit 920d254

Please sign in to comment.