mirror of
https://github.com/3b1b/manim.git
synced 2025-08-03 04:04:36 +08:00
Added DocStrings for all methods in Container, Scene, GraphScene, MovingCameraScene, SceneFileWriter, ThreeDScene, SpecialThreeDScene, ZoomedScene, VectorScene, and LinearTransformationScene. (#1040)
* Added DocStrings for methods in Container and Scene. Removed 2 unused imports from scene.py. * Added DocStrings for all methods in GraphScene, MovingCameraScene, SceneFileWriter, ThreeDScene, SpecialThreeDScene and ZoomedScene. * Added DocStrings for all methods in `VectorScene` and LinearTransformationScene... ...except `position_x_coordinate` and `position_y_coordinate` Co-authored-by: Aathish Sivasubrahmanian <aathishs@Aathishs-MacBook-Air.local>
This commit is contained in:
@ -20,6 +20,21 @@ from manimlib.utils.sounds import get_full_sound_file_path
|
||||
|
||||
|
||||
class SceneFileWriter(object):
|
||||
"""
|
||||
SceneFileWriter is the object that actually writes the animations
|
||||
played, into video files, using FFMPEG, and Sox, if sound is needed.
|
||||
This is mostly for Manim's internal use. You will rarely, if ever,
|
||||
have to use the methods for this class, unless tinkering with the very
|
||||
fabric of Manim's reality.
|
||||
|
||||
Some useful attributes are:
|
||||
"write_to_movie" (bool=False)
|
||||
Whether or not to write the animations into a video file.
|
||||
"png_mode" (str="RGBA")
|
||||
The PIL image mode to use when outputting PNGs
|
||||
"movie_file_extension" (str=".mp4")
|
||||
The file-type extension of the outputted video.
|
||||
"""
|
||||
CONFIG = {
|
||||
"write_to_movie": False,
|
||||
# TODO, save_pngs is doing nothing
|
||||
@ -44,6 +59,11 @@ class SceneFileWriter(object):
|
||||
|
||||
# Output directories and files
|
||||
def init_output_directories(self):
|
||||
"""
|
||||
This method initialises the directories to which video
|
||||
files will be written to and read from (within MEDIA_DIR).
|
||||
If they don't already exist, they will be created.
|
||||
"""
|
||||
module_directory = self.output_directory or self.get_default_module_directory()
|
||||
scene_name = self.file_name or self.get_default_scene_name()
|
||||
if self.save_last_frame:
|
||||
@ -90,17 +110,58 @@ class SceneFileWriter(object):
|
||||
))
|
||||
|
||||
def get_default_module_directory(self):
|
||||
"""
|
||||
This method gets the name of the directory containing
|
||||
the file that has the Scene that is being rendered.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
The name of the directory.
|
||||
"""
|
||||
filename = os.path.basename(self.input_file_path)
|
||||
root, _ = os.path.splitext(filename)
|
||||
return root
|
||||
|
||||
def get_default_scene_name(self):
|
||||
"""
|
||||
This method returns the default scene name
|
||||
which is the value of "file_name", if it exists and
|
||||
the actual name of the class that inherited from
|
||||
Scene in your animation script, if "file_name" is None.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
The default scene name.
|
||||
"""
|
||||
if self.file_name is None:
|
||||
return self.scene.__class__.__name__
|
||||
else:
|
||||
return self.file_name
|
||||
|
||||
def get_resolution_directory(self):
|
||||
"""
|
||||
This method gets the name of the directory that immediately contains the
|
||||
video file. This name is <height_in_pixels_of_video>p<frame_rate>
|
||||
E.G:
|
||||
If you are rendering an 854x480 px animation at 15fps, the name of the directory
|
||||
that immediately contains the video file will be
|
||||
480p15.
|
||||
The file structure should look something like:
|
||||
|
||||
MEDIA_DIR
|
||||
|--Tex
|
||||
|--texts
|
||||
|--videos
|
||||
|--<name_of_file_containing_scene>
|
||||
|--<height_in_pixels_of_video>p<frame_rate>
|
||||
|--<scene_name>.mp4
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
The name of the directory.
|
||||
"""
|
||||
pixel_height = self.scene.camera.pixel_height
|
||||
frame_rate = self.scene.camera.frame_rate
|
||||
return "{}p{}".format(
|
||||
@ -109,9 +170,32 @@ class SceneFileWriter(object):
|
||||
|
||||
# Directory getters
|
||||
def get_image_file_path(self):
|
||||
"""
|
||||
This returns the directory path to which any images will be
|
||||
written to.
|
||||
It is usually named "images", but can be changed by changing
|
||||
"image_file_path".
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
The path of the directory.
|
||||
"""
|
||||
return self.image_file_path
|
||||
|
||||
def get_next_partial_movie_path(self):
|
||||
"""
|
||||
Manim renders each play-like call in a short partial
|
||||
video file. All such files are then concatenated with
|
||||
the help of FFMPEG.
|
||||
|
||||
This method returns the path of the next partial movie.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
The path of the next partial movie.
|
||||
"""
|
||||
result = os.path.join(
|
||||
self.partial_movie_directory,
|
||||
"{:05}{}".format(
|
||||
@ -122,18 +206,46 @@ class SceneFileWriter(object):
|
||||
return result
|
||||
|
||||
def get_movie_file_path(self):
|
||||
"""
|
||||
Returns the final path of the written video file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
The path of the movie file.
|
||||
"""
|
||||
return self.movie_file_path
|
||||
|
||||
# Sound
|
||||
def init_audio(self):
|
||||
"""
|
||||
Preps the writer for adding audio to the movie.
|
||||
"""
|
||||
self.includes_sound = False
|
||||
|
||||
def create_audio_segment(self):
|
||||
"""
|
||||
Creates an empty, silent, Audio Segment.
|
||||
"""
|
||||
self.audio_segment = AudioSegment.silent()
|
||||
|
||||
def add_audio_segment(self, new_segment,
|
||||
time=None,
|
||||
gain_to_background=None):
|
||||
"""
|
||||
This method adds an audio segment from an
|
||||
AudioSegment type object and suitable parameters.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
new_segment (AudioSegment)
|
||||
The audio segment to add
|
||||
time (Union[int, float])
|
||||
the timestamp at which the
|
||||
sound should be added.
|
||||
gain_to_background
|
||||
The gain of the segment from the background.
|
||||
"""
|
||||
if not self.includes_sound:
|
||||
self.includes_sound = True
|
||||
self.create_audio_segment()
|
||||
@ -158,6 +270,25 @@ class SceneFileWriter(object):
|
||||
)
|
||||
|
||||
def add_sound(self, sound_file, time=None, gain=None, **kwargs):
|
||||
"""
|
||||
This method adds an audio segment from a sound file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
sound_file (str)
|
||||
The path to the sound file.
|
||||
|
||||
time (Union[float, int])
|
||||
The timestamp at which the audio should be added.
|
||||
|
||||
gain
|
||||
The gain of the given audio segment.
|
||||
|
||||
**kwargs
|
||||
This method uses add_audio_segment, so any keyword arguments
|
||||
used there can be referenced here.
|
||||
|
||||
"""
|
||||
file_path = get_full_sound_file_path(sound_file)
|
||||
new_segment = AudioSegment.from_file(file_path)
|
||||
if gain:
|
||||
@ -166,23 +297,62 @@ class SceneFileWriter(object):
|
||||
|
||||
# Writers
|
||||
def begin_animation(self, allow_write=False):
|
||||
"""
|
||||
Used internally by manim to stream the animation to FFMPEG for
|
||||
displaying or writing to a file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
allow_write (bool=False)
|
||||
Whether or not to write to a video file.
|
||||
"""
|
||||
if self.write_to_movie and allow_write:
|
||||
self.open_movie_pipe()
|
||||
|
||||
def end_animation(self, allow_write=False):
|
||||
"""
|
||||
Internally used by Manim to stop streaming to
|
||||
FFMPEG gracefully.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
allow_write (bool=False)
|
||||
Whether or not to write to a video file.
|
||||
"""
|
||||
if self.write_to_movie and allow_write:
|
||||
self.close_movie_pipe()
|
||||
|
||||
def write_frame(self, frame):
|
||||
"""
|
||||
Used internally by Manim to write a frame to
|
||||
the FFMPEG input buffer.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
frame (np.ndarray)
|
||||
Pixel array of the frame.
|
||||
"""
|
||||
if self.write_to_movie:
|
||||
self.writing_process.stdin.write(frame.tostring())
|
||||
|
||||
def save_final_image(self, image):
|
||||
"""
|
||||
The name is a misnomer. This method saves the image
|
||||
passed to it as an in the default image directory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image (np.ndarray)
|
||||
The pixel array of the image to save.
|
||||
"""
|
||||
file_path = self.get_image_file_path()
|
||||
image.save(file_path)
|
||||
self.print_file_ready_message(file_path)
|
||||
|
||||
def idle_stream(self):
|
||||
"""
|
||||
Doesn't write anything to the FFMPEG frame buffer.
|
||||
"""
|
||||
while self.stream_lock:
|
||||
a = datetime.datetime.now()
|
||||
self.update_frame()
|
||||
@ -196,6 +366,13 @@ class SceneFileWriter(object):
|
||||
sleep(frame_duration - time_diff)
|
||||
|
||||
def finish(self):
|
||||
"""
|
||||
Finishes writing to the FFMPEG buffer.
|
||||
Combines the partial movie files into the
|
||||
whole scene.
|
||||
If save_last_frame is True, saves the last
|
||||
frame in the default image directory.
|
||||
"""
|
||||
if self.write_to_movie:
|
||||
if hasattr(self, "writing_process"):
|
||||
self.writing_process.terminate()
|
||||
@ -205,6 +382,11 @@ class SceneFileWriter(object):
|
||||
self.save_final_image(self.scene.get_image())
|
||||
|
||||
def open_movie_pipe(self):
|
||||
"""
|
||||
Used internally by Manim to initalise
|
||||
FFMPEG and begin writing to FFMPEG's input
|
||||
buffer.
|
||||
"""
|
||||
file_path = self.get_next_partial_movie_path()
|
||||
temp_file_path = os.path.splitext(file_path)[0] + '_temp' + self.movie_file_extension
|
||||
|
||||
@ -243,6 +425,11 @@ class SceneFileWriter(object):
|
||||
self.writing_process = subprocess.Popen(command, stdin=subprocess.PIPE)
|
||||
|
||||
def close_movie_pipe(self):
|
||||
"""
|
||||
Used internally by Manim to gracefully stop writing to FFMPEG's
|
||||
input buffer, and move the temporary files into their permananant
|
||||
locations
|
||||
"""
|
||||
self.writing_process.stdin.close()
|
||||
self.writing_process.wait()
|
||||
shutil.move(
|
||||
@ -251,6 +438,11 @@ class SceneFileWriter(object):
|
||||
)
|
||||
|
||||
def combine_movie_files(self):
|
||||
"""
|
||||
Used internally by Manim to combine the separate
|
||||
partial movie files that make up a Scene into a single
|
||||
video file for that Scene.
|
||||
"""
|
||||
# Manim renders the scene as many smaller movie files
|
||||
# which are then concatenated to a larger one. The reason
|
||||
# for this is that sometimes video-editing is made easier when
|
||||
@ -339,4 +531,7 @@ class SceneFileWriter(object):
|
||||
self.print_file_ready_message(movie_file_path)
|
||||
|
||||
def print_file_ready_message(self, file_path):
|
||||
"""
|
||||
Prints the "File Ready" message to STDOUT.
|
||||
"""
|
||||
print("\nFile ready at {}\n".format(file_path))
|
||||
|
Reference in New Issue
Block a user