Module generativepy.movie
The movie consists of a sequence of frames, where each frame is a NumPy array. Movies are generated and processed using a lazy iterators tht generates frames on demand.
The movie module provides functionality to create video clips (or "scenes"), incorporate audio files, and compile separate scenes into complete movies.
Functions
def create_videoclip(frames, duration, frame_rate, audio_in=None)
-
Create a VideoClip object from a sequence of frames and an optional audio file.
Args
frames
- numpy arrays - the sequence of frames.
duration
- number - duration of clip in seconds.
frame_rate
- number - frame rate, frames per second.
audio_in
- str - file name of audio file, or None.
Returns
A
VideoClip
object. def duplicate_frame(frame, count)
-
Duplicate a single frame, multiple times.
Args
frame
- numpy array - the frame
count
- int - Number of times to duplicate
Returns
A generator object.
def normalise_array(array)
-
If greyscale array has a shape [a, b, 1] it must be normalised to [a, b] otherwise the pillow fromarray function will give an error.
This function first checks if normalisation is necessary, and then creates a new normalised array if required.
Args
array
- numpy array - the image data as a numpy array.
Returns
Normalised array. This will either be a new array (if normalisation was required) or the original array (if no normalisation was required).
def save_frame(outfile, frame)
-
Save a frame as a png image
Args
outfile
- str - full name and path of the file (.png extension optional)
frame
- numpy array - the frame
def save_frames(outfile, frames)
-
Save a sequence of frame as a sequence of png images
Args
outfile
- str - base name and path of the file (.png extension optional).
frames
- numpy arrays - the sequence of frames.
Classes
class MovieBuilder (frame_rate)
-
Builds up a movie from a set of clips.
Args
frame_rate
- number - frame rate, frames per second.
Expand source code
class MovieBuilder(): """ Builds up a movie from a set of clips. """ def __init__(self, frame_rate): """ Args: frame_rate: number - frame rate, frames per second. """ self.frame_rate = frame_rate self.frame_sources = [] self.audio_files = [] self.duration = [] def add_scene(self, frame_source_duration, audio_file=None): """ Add a scene (a sequence of frame plus an optional audio file). Note, due to the requirements of the MoviePy library, if the movie has sound then every scene must include a sound file (use a slient file if no sound is required for a particular scene). Alternatively, if the movie has no sound,then don;t include a sound file with any of the scenes. Also note that the sound file should be at least as long as the video duration. Args: frame_source_duration: tuple - frame_source, duration. frame_source is a iterator returning numpy frame objects, duration is the clip duration in seconds audio_file: str - name of MP3 file, or None. Returns: """ self.frame_sources.append(frame_source_duration[0]) self.duration.append(frame_source_duration[1]) self.audio_files.append(audio_file) def make_movie(self, video_out, source=None): """ Make a movie of either all the clips that have been added, or just a single clip if source is not None. Args: video_out: str - Filename of output file. source: int - set to index of a clip to use just that clip, or None to join all clips. """ if source is not None: video = create_videoclip(self.frame_sources[source], self.duration[source], self.frame_rate, self.audio_files[source]) else: clips = [create_videoclip(s, d, self.frame_rate, a) for s, d, a in zip(self.frame_sources, self.duration, self.audio_files)] video = concatenate_videoclips(clips) # Due to a bug in moviepy 1.0.1, when we write a video out in this mode the audio is not included. # So we write the video and audio out to separate temporary files. # We then use ffmpeg directly to combine the video and audio. temp_video_filename = temp_file(pathlib.Path(video_out).stem + "TEMP.mp4") temp_audio_filename = temp_file(pathlib.Path(video_out).stem + "TEMP.m4a") if not all(self.audio_files): if any(self.audio_files): logging.warning("MovieBuilder - some of the scenes have audio data, some do not, so the final video will have no audio data") video.write_videofile(video_out, codec="libx264", fps=self.frame_rate) else: video.write_videofile(temp_video_filename, temp_audiofile=temp_audio_filename, codec="libx264", remove_temp=False, audio_codec="aac", fps=self.frame_rate) command = ["ffmpeg", "-y", #approve output file overwite "-i", temp_video_filename, "-i", temp_audio_filename, "-c:v", "copy", "-c:a", "copy", "-shortest", "-r", str(self.frame_rate), video_out ] process = sp.run(command)
Methods
def add_scene(self, frame_source_duration, audio_file=None)
-
Add a scene (a sequence of frame plus an optional audio file).
Note, due to the requirements of the MoviePy library, if the movie has sound then every scene must include a sound file (use a slient file if no sound is required for a particular scene). Alternatively, if the movie has no sound,then don;t include a sound file with any of the scenes.
Also note that the sound file should be at least as long as the video duration.
Args
frame_source_duration
- tuple - frame_source, duration. frame_source is a iterator returning numpy frame objects, duration is the clip duration in seconds
audio_file
- str - name of MP3 file, or None.
Returns:
def make_movie(self, video_out, source=None)
-
Make a movie of either all the clips that have been added, or just a single clip if source is not None.
Args
video_out
- str - Filename of output file.
source
- int - set to index of a clip to use just that clip, or None to join all clips.