def combine_movie_files(self) -> None: kwargs = { "remove_non_integer_files": True, "extension": self.movie_file_extension, } if self.scene.start_at_animation_number is not None: kwargs["min_index"] = self.scene.start_at_animation_number if self.scene.end_at_animation_number is not None: kwargs["max_index"] = self.scene.end_at_animation_number else: kwargs["remove_indices_greater_than"] = self.scene.num_plays - 1 partial_movie_files = get_sorted_integer_files( self.partial_movie_directory, **kwargs) if len(partial_movie_files) == 0: log.warning("No animations in this scene") return # Write a file partial_file_list.txt containing all # partial movie files file_list = os.path.join(self.partial_movie_directory, "partial_movie_file_list.txt") with open(file_list, 'w') as fp: for pf_path in partial_movie_files: if os.name == 'nt': pf_path = pf_path.replace('\\', '/') fp.write(f"file \'{pf_path}\'\n") movie_file_path = self.get_movie_file_path() commands = [ FFMPEG_BIN, '-y', # overwrite output file if it exists '-f', 'concat', '-safe', '0', '-i', file_list, '-loglevel', 'error', '-c', 'copy', movie_file_path ] if not self.includes_sound: commands.insert(-1, '-an') combine_process = sp.Popen(commands) combine_process.wait()
def combine_movie_files(self): # 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 # one works with the broken up scene, which effectively has # 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": self.movie_file_extension, } if self.scene.start_at_animation_number is not None: kwargs["min_index"] = self.scene.start_at_animation_number if self.scene.end_at_animation_number is not None: kwargs["max_index"] = self.scene.end_at_animation_number else: kwargs["remove_indices_greater_than"] = self.scene.num_plays - 1 partial_movie_files = get_sorted_integer_files( self.partial_movie_directory, **kwargs ) if len(partial_movie_files) == 0: print("No animations in this scene") return # Write a file partial_file_list.txt containing all # partial movie files file_list = os.path.join( self.partial_movie_directory, "partial_movie_file_list.txt" ) with open(file_list, 'w') as fp: for pf_path in partial_movie_files: if os.name == 'nt': pf_path = pf_path.replace('\\', '/') fp.write("file \'{}\'\n".format(pf_path)) movie_file_path = self.get_movie_file_path() commands = [ FFMPEG_BIN, '-y', # overwrite output file if it exists '-f', 'concat', '-safe', '0', '-i', file_list, '-c', 'copy', '-loglevel', 'error', movie_file_path ] if not self.includes_sound: commands.insert(-1, '-an') combine_process = subprocess.Popen(commands) combine_process.wait() if self.includes_sound: sound_file_path = movie_file_path.replace( self.movie_file_extension, ".wav" ) # Makes sure sound file length will match video file self.add_audio_segment(AudioSegment.silent(0)) self.audio_segment.export( sound_file_path, bitrate='312k', ) temp_file_path = movie_file_path.replace(".", "_temp.") commands = [ "ffmpeg", "-i", movie_file_path, "-i", sound_file_path, '-y', # overwrite output file if it exists "-c:v", "copy", "-c:a", "aac", "-b:a", "320k", # select video stream from first file "-map", "0:v:0", # select audio stream from second file "-map", "1:a:0", '-loglevel', 'error', # "-shortest", temp_file_path, ] subprocess.call(commands) shutil.move(temp_file_path, movie_file_path) subprocess.call(["rm", sound_file_path]) self.print_file_ready_message(movie_file_path)
def combine_movie_files(self): # 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 # one works with the broken up scene, which effectively has # 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": self.movie_file_extension, } if self.scene.start_at_animation_number is not None: kwargs["min_index"] = self.scene.start_at_animation_number if self.scene.end_at_animation_number is not None: kwargs["max_index"] = self.scene.end_at_animation_number else: kwargs["remove_indices_greater_than"] = self.scene.num_plays - 1 partial_movie_files = get_sorted_integer_files( self.partial_movie_directory, **kwargs) if len(partial_movie_files) == 0: print("No animations in this scene") return # Write a file partial_file_list.txt containing all # partial movie files file_list = os.path.join(self.partial_movie_directory, "partial_movie_file_list.txt") with open(file_list, 'w') as fp: for pf_path in partial_movie_files: if os.name == 'nt': pf_path = pf_path.replace('\\', '/') fp.write("file \'{}\'\n".format(pf_path)) movie_file_path = self.get_movie_file_path() commands = [ FFMPEG_BIN, '-y', # overwrite output file if it exists '-f', 'concat', '-safe', '0', '-i', file_list, '-loglevel', 'error', '-c', 'copy', movie_file_path ] if not self.includes_sound: commands.insert(-1, '-an') combine_process = subprocess.Popen(commands) combine_process.wait() if self.includes_sound: sound_file_path = movie_file_path.replace( self.movie_file_extension, ".wav") # Makes sure sound file length will match video file self.add_audio_segment(AudioSegment.silent(0)) self.audio_segment.export( sound_file_path, bitrate='312k', ) temp_file_path = movie_file_path.replace(".", "_temp.") commands = [ "ffmpeg", "-i", movie_file_path, "-i", sound_file_path, '-y', # overwrite output file if it exists "-c:v", "copy", "-c:a", "aac", "-b:a", "320k", # select video stream from first file "-map", "0:v:0", # select audio stream from second file "-map", "1:a:0", '-loglevel', 'error', # "-shortest", temp_file_path, ] subprocess.call(commands) shutil.move(temp_file_path, movie_file_path) subprocess.call(["rm", sound_file_path]) self.print_file_ready_message(movie_file_path)