-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Added Scene caching #166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added Scene caching #166
Changes from all commits
384b84a
deeade5
04d8c45
555b304
1e6e7aa
b5ac0e2
ac8a598
39b39d8
ae3d3d4
6488252
d02309b
f1da2ff
83b03eb
79553dd
c5a0b1f
3fb8fe2
9ff6d41
64d82a3
ebfcbc1
7f98b1c
d10ee72
9c5dbcd
d497e1c
b27a416
d52d9f3
8c3276c
cdfbfa9
8499535
0ace9a6
b1a378e
2c95a7e
4844847
1d71a05
9b8cb61
5427491
f2e924b
901934d
a03da90
ec0bdaf
6fd8c4b
3100156
66631e8
90b69c5
18ccc27
7bca134
4f303e4
ccad56b
a36dfbf
64403c0
3d0cd01
1198108
8bcc05a
e0fc6e5
2d1d58d
e5e1597
f9cc9ed
e3ab30a
947e146
7a3e1dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,7 @@ | |
from ..utils.config_ops import digest_config | ||
from ..utils.file_ops import guarantee_existence | ||
from ..utils.file_ops import add_extension_if_not_present | ||
from ..utils.file_ops import get_sorted_integer_files | ||
from ..utils.file_ops import modify_atime | ||
from ..utils.sounds import get_full_sound_file_path | ||
|
||
|
||
|
@@ -170,8 +170,9 @@ def get_next_partial_movie_path(self): | |
""" | ||
result = os.path.join( | ||
self.partial_movie_directory, | ||
"{:05}{}".format( | ||
self.scene.num_plays, file_writer_config["movie_file_extension"], | ||
"{}{}".format( | ||
self.scene.play_hashes_list[self.scene.num_plays], | ||
file_writer_config["movie_file_extension"], | ||
), | ||
) | ||
return result | ||
|
@@ -351,6 +352,10 @@ def finish(self): | |
if hasattr(self, "writing_process"): | ||
self.writing_process.terminate() | ||
self.combine_movie_files() | ||
if file_writer_config["flush_cache"]: | ||
self.flush_cache_directory() | ||
else: | ||
self.clean_cache() | ||
if file_writer_config["save_last_frame"]: | ||
self.scene.update_frame(ignore_skipping=True) | ||
self.save_final_image(self.scene.get_image()) | ||
|
@@ -421,6 +426,28 @@ def close_movie_pipe(self): | |
shutil.move( | ||
self.temp_partial_movie_file_path, self.partial_movie_file_path, | ||
) | ||
logger.debug( | ||
f"Animation {self.scene.num_plays} : Partial movie file written in {self.partial_movie_file_path}" | ||
) | ||
|
||
def is_already_cached(self, hash_invocation): | ||
"""Will check if a file named with `hash_invocation` exists. | ||
|
||
Parameters | ||
---------- | ||
hash_invocation : :class:`str` | ||
The hash corresponding to an invocation to either `scene.play` or `scene.wait`. | ||
|
||
Returns | ||
------- | ||
:class:`bool` | ||
Whether the file exists. | ||
""" | ||
path = os.path.join( | ||
self.partial_movie_directory, | ||
"{}{}".format(hash_invocation, self.movie_file_extension), | ||
) | ||
return os.path.exists(path) | ||
|
||
def combine_movie_files(self): | ||
""" | ||
|
@@ -435,34 +462,27 @@ def combine_movie_files(self): | |
# cuts at all the places you might want. But for viewing | ||
# the scene as a whole, one of course wants to see it as a | ||
# single piece. | ||
kwargs = { | ||
"remove_non_integer_files": True, | ||
"extension": file_writer_config["movie_file_extension"], | ||
} | ||
if file_writer_config["from_animation_number"] is not None: | ||
kwargs["min_index"] = file_writer_config["from_animation_number"] | ||
if file_writer_config["upto_animation_number"] not in [None, np.inf]: | ||
kwargs["max_index"] = file_writer_config["upto_animation_number"] | ||
else: | ||
kwargs["remove_indices_greater_than"] = self.scene.num_plays - 1 | ||
Comment on lines
-442
to
-447
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: where did these go? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has been removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait so the names of the files in partial_movie_files are changing too? |
||
partial_movie_files = get_sorted_integer_files( | ||
self.partial_movie_directory, **kwargs | ||
) | ||
partial_movie_files = [ | ||
os.path.join( | ||
self.partial_movie_directory, | ||
"{}{}".format(hash_play, file_writer_config["movie_file_extension"]), | ||
) | ||
for hash_play in self.scene.play_hashes_list | ||
] | ||
if len(partial_movie_files) == 0: | ||
logger.error("No animations in this scene") | ||
return | ||
|
||
# Write a file partial_file_list.txt containing all | ||
# partial movie files | ||
# partial movie files. This is used by FFMPEG. | ||
file_list = os.path.join( | ||
self.partial_movie_directory, "partial_movie_file_list.txt" | ||
) | ||
with open(file_list, "w") as fp: | ||
fp.write("# This file is used internally by FFMPEG.\n") | ||
for pf_path in partial_movie_files: | ||
if os.name == "nt": | ||
pf_path = pf_path.replace("\\", "/") | ||
fp.write("file 'file:{}'\n".format(pf_path)) | ||
|
||
movie_file_path = self.get_movie_file_path() | ||
commands = [ | ||
FFMPEG_BIN, | ||
|
@@ -527,6 +547,46 @@ def combine_movie_files(self): | |
os.remove(sound_file_path) | ||
|
||
self.print_file_ready_message(movie_file_path) | ||
if file_writer_config["write_to_movie"]: | ||
for file_path in partial_movie_files: | ||
# We have to modify the accessed time so if we have to clean the cache we remove the one used the longest. | ||
modify_atime(file_path) | ||
|
||
def clean_cache(self): | ||
"""Will clean the cache by removing the partial_movie_files used by manim the longest ago.""" | ||
cached_partial_movies = [ | ||
os.path.join(self.partial_movie_directory, file_name) | ||
for file_name in os.listdir(self.partial_movie_directory) | ||
if file_name != "partial_movie_file_list.txt" | ||
] | ||
if len(cached_partial_movies) > file_writer_config["max_files_cached"]: | ||
number_files_to_delete = ( | ||
len(cached_partial_movies) - file_writer_config["max_files_cached"] | ||
) | ||
oldest_files_to_delete = sorted( | ||
[partial_movie_file for partial_movie_file in cached_partial_movies], | ||
key=os.path.getatime, | ||
)[:number_files_to_delete] | ||
# oldest_file_path = min(cached_partial_movies, key=os.path.getatime) | ||
for file_to_delete in oldest_files_to_delete: | ||
os.remove(file_to_delete) | ||
logger.info( | ||
f"The partial movie directory is full (> {file_writer_config['max_files_cached']} files). Therefore, manim has removed {number_files_to_delete} file(s) used by it the longest ago." | ||
+ "You can change this behaviour by changing max_files_cached in config." | ||
) | ||
|
||
def flush_cache_directory(self): | ||
"""Delete all the cached partial movie files""" | ||
cached_partial_movies = [ | ||
os.path.join(self.partial_movie_directory, file_name) | ||
for file_name in os.listdir(self.partial_movie_directory) | ||
if file_name != "partial_movie_file_list.txt" | ||
] | ||
for f in cached_partial_movies: | ||
os.remove(f) | ||
logger.info( | ||
f"Cache flushed. {len(cached_partial_movies)} file(s) deleted in {self.partial_movie_directory}." | ||
) | ||
|
||
def print_file_ready_message(self, file_path): | ||
""" | ||
|
Uh oh!
There was an error while loading. Please reload this page.