mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Fix writing to gifs
This commit is contained in:
parent
0ac155d150
commit
a58772db87
2 changed files with 28 additions and 31 deletions
|
@ -65,7 +65,7 @@ def parse_cli():
|
||||||
help="Save each frame as a png",
|
help="Save each frame as a png",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-i", "--save_as_gif",
|
"-i", "--gif",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Save the video as gif",
|
help="Save the video as gif",
|
||||||
)
|
)
|
||||||
|
@ -172,15 +172,21 @@ def get_configuration(args):
|
||||||
custom_defaults = get_custom_defaults()
|
custom_defaults = get_custom_defaults()
|
||||||
|
|
||||||
write_file = any([args.write_file, args.open, args.finder])
|
write_file = any([args.write_file, args.open, args.finder])
|
||||||
|
if args.transparent:
|
||||||
|
file_ext = ".mov"
|
||||||
|
elif args.gif:
|
||||||
|
file_ext = ".gif"
|
||||||
|
else:
|
||||||
|
file_ext = ".mp4"
|
||||||
|
|
||||||
file_writer_config = {
|
file_writer_config = {
|
||||||
"write_to_movie": not args.skip_animations and write_file,
|
"write_to_movie": not args.skip_animations and write_file,
|
||||||
"break_into_partial_movies": custom_defaults["break_into_partial_movies"],
|
"break_into_partial_movies": custom_defaults["break_into_partial_movies"],
|
||||||
"save_last_frame": args.skip_animations and write_file,
|
"save_last_frame": args.skip_animations and write_file,
|
||||||
"save_pngs": args.save_pngs,
|
"save_pngs": args.save_pngs,
|
||||||
"save_as_gif": args.save_as_gif,
|
|
||||||
# If -t is passed in (for transparent), this will be RGBA
|
# If -t is passed in (for transparent), this will be RGBA
|
||||||
"png_mode": "RGBA" if args.transparent else "RGB",
|
"png_mode": "RGBA" if args.transparent else "RGB",
|
||||||
"movie_file_extension": ".mov" if args.transparent else ".mp4",
|
"movie_file_extension": file_ext,
|
||||||
"mirror_module_path": custom_defaults["directories"]["mirror_module_path"],
|
"mirror_module_path": custom_defaults["directories"]["mirror_module_path"],
|
||||||
"output_directory": args.video_dir or custom_defaults["directories"]["output"],
|
"output_directory": args.video_dir or custom_defaults["directories"]["output"],
|
||||||
"file_name": args.file_name,
|
"file_name": args.file_name,
|
||||||
|
|
|
@ -23,7 +23,6 @@ class SceneFileWriter(object):
|
||||||
"png_mode": "RGBA",
|
"png_mode": "RGBA",
|
||||||
"save_last_frame": False,
|
"save_last_frame": False,
|
||||||
"movie_file_extension": ".mp4",
|
"movie_file_extension": ".mp4",
|
||||||
"gif_file_extension": ".gif",
|
|
||||||
# Should the path of output files mirror the directory
|
# Should the path of output files mirror the directory
|
||||||
# structure of the module holding the scene?
|
# structure of the module holding the scene?
|
||||||
"mirror_module_path": False,
|
"mirror_module_path": False,
|
||||||
|
@ -60,10 +59,6 @@ class SceneFileWriter(object):
|
||||||
movie_dir = guarantee_existence(os.path.join(out_dir, "videos"))
|
movie_dir = guarantee_existence(os.path.join(out_dir, "videos"))
|
||||||
movie_file = add_extension_if_not_present(scene_name, self.movie_file_extension)
|
movie_file = add_extension_if_not_present(scene_name, self.movie_file_extension)
|
||||||
self.movie_file_path = os.path.join(movie_dir, movie_file)
|
self.movie_file_path = os.path.join(movie_dir, movie_file)
|
||||||
self.gif_file_path = self.movie_file_path.replace(
|
|
||||||
self.movie_file_extension,
|
|
||||||
self.gif_file_extension,
|
|
||||||
)
|
|
||||||
if self.break_into_partial_movies:
|
if self.break_into_partial_movies:
|
||||||
self.partial_movie_directory = guarantee_existence(os.path.join(
|
self.partial_movie_directory = guarantee_existence(os.path.join(
|
||||||
movie_dir, "partial_movie_files", scene_name,
|
movie_dir, "partial_movie_files", scene_name,
|
||||||
|
@ -158,24 +153,12 @@ class SceneFileWriter(object):
|
||||||
if self.break_into_partial_movies and self.write_to_movie:
|
if self.break_into_partial_movies and self.write_to_movie:
|
||||||
self.close_movie_pipe()
|
self.close_movie_pipe()
|
||||||
|
|
||||||
def write_frame(self, camera):
|
|
||||||
if self.write_to_movie:
|
|
||||||
raw_bytes = camera.get_raw_fbo_data()
|
|
||||||
self.writing_process.stdin.write(raw_bytes)
|
|
||||||
|
|
||||||
def save_final_image(self, image):
|
|
||||||
file_path = self.get_image_file_path()
|
|
||||||
image.save(file_path)
|
|
||||||
self.print_file_ready_message(file_path)
|
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
if self.write_to_movie:
|
if self.write_to_movie:
|
||||||
if not self.break_into_partial_movies:
|
|
||||||
self.close_movie_pipe()
|
|
||||||
if self.writing_process is not None:
|
|
||||||
self.writing_process.terminate()
|
|
||||||
if self.break_into_partial_movies:
|
if self.break_into_partial_movies:
|
||||||
self.combine_movie_files()
|
self.combine_movie_files()
|
||||||
|
else:
|
||||||
|
self.close_movie_pipe()
|
||||||
if self.includes_sound:
|
if self.includes_sound:
|
||||||
self.add_sound_to_video()
|
self.add_sound_to_video()
|
||||||
self.print_file_ready_message(self.get_movie_file_path())
|
self.print_file_ready_message(self.get_movie_file_path())
|
||||||
|
@ -187,7 +170,8 @@ class SceneFileWriter(object):
|
||||||
|
|
||||||
def open_movie_pipe(self, file_path):
|
def open_movie_pipe(self, file_path):
|
||||||
stem, ext = os.path.splitext(file_path)
|
stem, ext = os.path.splitext(file_path)
|
||||||
temp_file_path = stem + "_temp" + ext
|
self.final_file_path = file_path
|
||||||
|
self.temp_file_path = stem + "_temp" + ext
|
||||||
|
|
||||||
fps = self.scene.camera.frame_rate
|
fps = self.scene.camera.frame_rate
|
||||||
width, height = self.scene.camera.get_pixel_shape()
|
width, height = self.scene.camera.get_pixel_shape()
|
||||||
|
@ -204,30 +188,32 @@ class SceneFileWriter(object):
|
||||||
'-an', # Tells FFMPEG not to expect any audio
|
'-an', # Tells FFMPEG not to expect any audio
|
||||||
'-loglevel', 'error',
|
'-loglevel', 'error',
|
||||||
]
|
]
|
||||||
# TODO, the test for a transparent background should not be based on
|
|
||||||
# the file extension.
|
|
||||||
if self.movie_file_extension == ".mov":
|
if self.movie_file_extension == ".mov":
|
||||||
# This is if the background of the exported
|
# This is if the background of the exported
|
||||||
# video should be transparent.
|
# video should be transparent.
|
||||||
command += [
|
command += [
|
||||||
'-vcodec', 'qtrle',
|
'-vcodec', 'qtrle',
|
||||||
]
|
]
|
||||||
|
elif self.movie_file_extension == ".gif":
|
||||||
|
command += []
|
||||||
else:
|
else:
|
||||||
command += [
|
command += [
|
||||||
'-vcodec', 'libx264',
|
'-vcodec', 'libx264',
|
||||||
'-pix_fmt', 'yuv420p',
|
'-pix_fmt', 'yuv420p',
|
||||||
]
|
]
|
||||||
command += [temp_file_path]
|
command += [self.temp_file_path]
|
||||||
self.writing_process = sp.Popen(command, stdin=sp.PIPE)
|
self.writing_process = sp.Popen(command, stdin=sp.PIPE)
|
||||||
self.temp_file_path = temp_file_path
|
|
||||||
|
def write_frame(self, camera):
|
||||||
|
if self.write_to_movie:
|
||||||
|
raw_bytes = camera.get_raw_fbo_data()
|
||||||
|
self.writing_process.stdin.write(raw_bytes)
|
||||||
|
|
||||||
def close_movie_pipe(self):
|
def close_movie_pipe(self):
|
||||||
self.writing_process.stdin.close()
|
self.writing_process.stdin.close()
|
||||||
self.writing_process.wait()
|
self.writing_process.wait()
|
||||||
shutil.move(
|
self.writing_process.terminate()
|
||||||
self.temp_file_path,
|
shutil.move(self.temp_file_path, self.final_file_path)
|
||||||
self.temp_file_path.replace("_temp", ""),
|
|
||||||
)
|
|
||||||
|
|
||||||
def combine_movie_files(self):
|
def combine_movie_files(self):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
|
@ -308,6 +294,11 @@ class SceneFileWriter(object):
|
||||||
shutil.move(temp_file_path, movie_file_path)
|
shutil.move(temp_file_path, movie_file_path)
|
||||||
os.remove(sound_file_path)
|
os.remove(sound_file_path)
|
||||||
|
|
||||||
|
def save_final_image(self, image):
|
||||||
|
file_path = self.get_image_file_path()
|
||||||
|
image.save(file_path)
|
||||||
|
self.print_file_ready_message(file_path)
|
||||||
|
|
||||||
def print_file_ready_message(self, file_path):
|
def print_file_ready_message(self, file_path):
|
||||||
print(f"\nFile ready at {file_path}\n")
|
print(f"\nFile ready at {file_path}\n")
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue