def convert_gif_to_video(ffmpeg_dir: str, input_path: str, output_path: str, output_options=None) -> None: assert get_operating_system() != "win32" or os.path.exists(ffmpeg_dir), \ "%s does not exist" % ffmpeg_dir execute = [ ffmpeg_dir, "-i", input_path, ] options = get_options_from_section( output_options["ffmpeg"]['convert_video_to_gif']['output_options'], ffmpeg_command=True) for item in options: execute.append(item) execute.append(output_path) print(execute) process = subprocess.Popen(execute, stdout=open(os.devnull, 'w'), stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=False) stdout, stderr = process.communicate()
def __init__(self, ffmpeg_binary: Path, input_video: Path, width: int, height: int, block_size: int, output_options_original: dict): self.__count: int = 0 self._width, self._height = get_a_valid_input_resolution( width, height, block_size) self._dtype = np.uint8 self._block_size = block_size self._output_options_original = output_options_original extraction_args = [ str(ffmpeg_binary), "-vsync", "1", "-loglevel", "panic", "-i", str(input_video) ] fixed_resolution = _check_and_fix_resolution( input_file=str(input_video), block_size=block_size, output_options_original=output_options_original) print("pre output options") options = get_options_from_section( fixed_resolution["ffmpeg"]["pre_process_video"]['output_options'], ffmpeg_command=True) for item in options: extraction_args.append(item) extraction_args.extend([ "-c:v", "rawvideo", "-f", "rawvideo", "-pix_fmt", "rgb24", "-an", "-" ]) pprint(extraction_args) self.ffmpeg = subprocess.Popen(extraction_args, stdout=subprocess.PIPE)
def _setup_pipe(self) -> None: self.log.info("Setting up pipe Called") # load variables.. output_no_sound = self.output_no_sound frame_rate = str(self.context.frame_rate) output_no_sound = output_no_sound ffmpeg_dir = load_executable_paths_yaml()['ffmpeg'] dar = self.context.video_settings.dar # constructing the pipe command... ffmpeg_pipe_command = [ffmpeg_dir, "-r", frame_rate] options = get_options_from_section( self.context.service_request.output_options["ffmpeg"]["pipe_video"] ['output_options'], ffmpeg_command=True) for item in options: ffmpeg_pipe_command.append(item) ffmpeg_pipe_command.append("-r") ffmpeg_pipe_command.append(frame_rate) ffmpeg_pipe_command.append(output_no_sound) # Starting the Pipe Command console_output = open( self.context.console_output_dir + "pipe_output.txt", "w") console_output.write(str(ffmpeg_pipe_command)) self.log.info("ffmpeg_pipe_command %s" % str(ffmpeg_pipe_command)) self.ffmpeg_pipe_subprocess = subprocess.Popen(ffmpeg_pipe_command, stdin=subprocess.PIPE, stdout=console_output)
def divide_and_reencode_video(ffmpeg_path: str, ffprobe_path: str, input_video: str, output_options: dict, divide: int, output_dir: str): """ Attempts to divide a video into N different segments, using the ffmpeg segment_time argument. See the reading I referenced here: https://superuser.com/questions/692714/how-to-split-videos-with-ffmpeg-and-segment-times-option Note that this will not perfectly divide the video into N different, equally sized chunks, but rather will cut them where keyframes allow them to be split. Args: ffmpeg_path: ffmpeg binary ffprobe_path: ffprobe binary input_video: File to be split output_options: Dictionary containing the loaded ./config_files/output_options.yaml divide: N divisions. output_dir: Where to save split_video%d.mkv's. Returns: Nothing, but split_video%d.mkv files will appear in output_dir. """ import math seconds = int( get_seconds(ffprobe_dir=ffprobe_path, input_video=input_video)) ratio = math.ceil(seconds / divide) frame_rate = VideoSettings(ffprobe_dir=ffprobe_path, video_file=input_video).frame_rate execute = [ ffmpeg_path, "-i", input_video, "-f", "segment", "-segment_time", str(ratio), "-r", str(frame_rate) ] options = get_options_from_section( output_options["ffmpeg"]['pre_process_video']['output_options'], ffmpeg_command=True) for element in options: execute.append(element) execute.append(os.path.join(output_dir, "split_video%d.mkv")) return_bytes = subprocess.run(execute, check=True, stdout=subprocess.PIPE).stdout return_string = return_bytes.decode("utf-8") return return_string
def re_encode_video(ffmpeg_dir: str, ffprobe_dir: str, output_options: dict, input_file: str, output_file: str, console_output=None) -> None: from dandere2x.dandere2xlib.wrappers.ffmpeg.videosettings import VideoSettings """ #todo """ if console_output: assert type(console_output) == str logger = logging.getLogger("root") video_settings = VideoSettings(ffmpeg_dir=ffmpeg_dir, ffprobe_dir=ffprobe_dir, video_file=input_file) frame_rate = video_settings.frame_rate extract_frames_command = [ffmpeg_dir] hw_accel = output_options["ffmpeg"]["pre_process_video"]["-hwaccel"] if hw_accel is not None: extract_frames_command.append("-hwaccel") extract_frames_command.append(hw_accel) extract_frames_command.extend(["-i", input_file]) extract_frames_options = \ get_options_from_section(output_options["ffmpeg"]['pre_process_video']['output_options'], ffmpeg_command=True) for element in extract_frames_options: extract_frames_command.append(element) extract_frames_command.append("-r") extract_frames_command.append(str(frame_rate)) extract_frames_command.extend([output_file]) logger.warning("Re-encoding your video, this may take some time.") process = subprocess.Popen(extract_frames_command, stdout=sys.stdout, stderr=sys.stdout, stdin=subprocess.PIPE, shell=False) stdout, stderr = process.communicate()
def _construct_upscale_command(self) -> list: waifu2x_vulkan_upscale_frame_command = [ self.waifu2x_vulkan_path, "-i", "[input_file]", "-s", str(self.context.service_request.scale_factor) ] waifu2x_vulkan_options = get_options_from_section( self.context.service_request.output_options["waifu2x_ncnn_vulkan"] ["output_options"]) # add custom options to waifu2x_vulkan for element in waifu2x_vulkan_options: waifu2x_vulkan_upscale_frame_command.append(element) waifu2x_vulkan_upscale_frame_command.extend(["-o", "[output_file]"]) return waifu2x_vulkan_upscale_frame_command
def _construct_upscale_command(self) -> list: upscale_command = [ self.waifu2x_caffe_path, "-i", "[input_file]", "-n", str(self.context.service_request.denoise_level), "-s", str(self.context.service_request.scale_factor) ] optional_paramaters = get_options_from_section( self.context.service_request.output_options["waifu2x_caffe"] ["output_options"]) # add optional paramaters to upscaling command. for element in optional_paramaters: upscale_command.append(element) upscale_command.extend(["-o", "[output_file]"]) return upscale_command
def migrate_tracks_contextless(ffmpeg_dir: str, no_audio: str, file_dir: str, output_file: str, output_options: dict, console_output_dir=None): """ Add the audio tracks from the original video to the output video. """ log = logging.getLogger("root") # to remove def convert(lst): return ' '.join(lst) log = logging.getLogger() migrate_tracks_command = [ ffmpeg_dir, "-i", no_audio, "-i", file_dir, "-map", "0:v?", "-map", "1:a?", "-map", "1:s?", "-map", "1:d?", "-map", "1:t?" ] options = get_options_from_section( output_options["ffmpeg"]['migrate_audio']['output_options'], ffmpeg_command=True) for element in options: migrate_tracks_command.append(element) migrate_tracks_command.extend([str(output_file)]) log.info("Migrating tracks %s " % convert(migrate_tracks_command)) console_output = get_console_output(__name__, console_output_dir) log.info("Writing files to %s" % str(console_output_dir)) log.info("Migrate Command: %s" % convert(migrate_tracks_command)) subprocess.call(migrate_tracks_command, shell=False, stderr=console_output, stdout=console_output) log.info("Finished migrating to file: %s" % output_file)
def _construct_upscale_command(self) -> list: waifu2x_converter_cpp_upscale_command = [ self.waifu2x_converter_cpp_path, "-i", "[input_file]", "--noise-level", str(self.context.service_request.denoise_level), "--scale-ratio", str(self.context.service_request.scale_factor) ] waifu2x_conv_options = get_options_from_section( self.context.service_request.output_options["waifu2x_converter"] ["output_options"]) # add custom options to waifu2x_vulkan for element in waifu2x_conv_options: waifu2x_converter_cpp_upscale_command.append(element) waifu2x_converter_cpp_upscale_command.extend(["-o", "[output_file]"]) return waifu2x_converter_cpp_upscale_command
def re_encode_video(ffmpeg_dir: str, ffprobe_dir: str, output_options: dict, input_file: str, output_file: str, console_output=None) -> None: """ #todo """ if console_output: assert type(console_output) == str logger = logging.getLogger(__name__) video_settings = VideoSettings(ffprobe_dir=ffprobe_dir, video_file=input_file) frame_rate = video_settings.frame_rate extract_frames_command = [ffmpeg_dir, "-i", input_file] extract_frames_options = \ get_options_from_section(output_options["ffmpeg"]['pre_process_video']['output_options'], ffmpeg_command=True) for element in extract_frames_options: extract_frames_command.append(element) extract_frames_command.append("-r") extract_frames_command.append(str(frame_rate)) extract_frames_command.extend([output_file]) process = subprocess.Popen(extract_frames_command, stdout=open(os.devnull, 'w'), stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=False) stdout, stderr = process.communicate()
video_settings = VideoSettings(ffprobe_dir=ffprobe_dir, video_file=input_file) frame_rate = video_settings.frame_rate extract_frames_command = [ffmpeg_dir] # walrus operator go brrrr if (hw_accel := output_options["ffmpeg"]["pre_process_video"]["-hwaccel"] ) is not None: extract_frames_command.append("-hwaccel") extract_frames_command.append(hw_accel) extract_frames_command.extend(["-i", input_file]) extract_frames_options = \ get_options_from_section(output_options["ffmpeg"]['pre_process_video']['output_options'], ffmpeg_command=True) for element in extract_frames_options: extract_frames_command.append(element) extract_frames_command.append("-r") extract_frames_command.append(str(frame_rate)) extract_frames_command.extend([output_file]) logger.warning("Re-encoding your video, this may take some time.") process = subprocess.Popen(extract_frames_command, stdout=sys.stdout, stderr=sys.stdout, stdin=subprocess.PIPE, shell=False)
class Pipe(threading.Thread): """ The pipe class allows images (Frame.py) to be processed into a video directly. It does this by "piping" images to ffmpeg, thus removing the need for storing the processed images onto the disk. """ def __init__(self, output_no_sound: str, context: Dandere2xServiceContext, controller: Dandere2xController): threading.Thread.__init__(self, name="Pipe Thread") # load context self.context = context self.controller = controller self.output_no_sound = output_no_sound self.log = logging.getLogger(name=self.context.service_request.input_file) # class specific self.ffmpeg_pipe_subprocess = None self.alive = False self.images_to_pipe = [] self.buffer_limit = 20 self.lock_buffer = False def kill(self) -> None: self.log.info("Kill called.") self.alive = False def run(self) -> None: self.log.info("Run Called") self.alive = True self._setup_pipe() # keep piping images to ffmpeg while this thread is supposed to be kept alive. while self.alive: if len(self.images_to_pipe) > 0: img = self.images_to_pipe.pop(0).get_pil_image() # get the first image and remove it from list img.save(self.ffmpeg_pipe_subprocess.stdin, format="jpeg", quality=100) else: time.sleep(0.1) # if the thread is killed for whatever reason, finish writing the remainder of the images to the video file. while self.images_to_pipe: pil_image = self.images_to_pipe.pop(0).get_pil_image() pil_image.save(self.ffmpeg_pipe_subprocess.stdin, format="jpeg", quality=100) self.ffmpeg_pipe_subprocess.stdin.close() self.ffmpeg_pipe_subprocess.wait() # ensure thread is dead (can be killed with controller.kill() ) self.alive = False # todo: Implement this without a 'while true' def save(self, frame): """ Try to add an image to image_to_pipe buffer. If there's too many images in the buffer, simply wait until the buffer clears. """ while True: if len(self.images_to_pipe) < self.buffer_limit: self.images_to_pipe.append(frame) break time.sleep(0.05) def _setup_pipe(self) -> None: self.log.info("Setting up pipe Called") # load variables.. output_no_sound = self.output_no_sound frame_rate = str(self.context.frame_rate) output_no_sound = output_no_sound ffmpeg_dir = load_executable_paths_yaml()['ffmpeg'] dar = self.context.video_settings.dar # constructing the pipe command... ffmpeg_pipe_command = [ffmpeg_dir] # walrus operator go brrrr if (hw_accel := self.context.service_request.output_options["ffmpeg"]["pipe_video"]["-hwaccel"]) is not None: ffmpeg_pipe_command.append("-hwaccel") ffmpeg_pipe_command.append(hw_accel) ffmpeg_pipe_command.extend(["-r", frame_rate]) options = get_options_from_section( self.context.service_request.output_options["ffmpeg"]["pipe_video"]['output_options'], ffmpeg_command=True) for item in options: ffmpeg_pipe_command.append(item) ffmpeg_pipe_command.append("-r") ffmpeg_pipe_command.append(frame_rate) ffmpeg_pipe_command.append(output_no_sound) # Starting the Pipe Command console_output = open(self.context.console_output_dir + "pipe_output.txt", "w") console_output.write(str(ffmpeg_pipe_command)) self.log.info("ffmpeg_pipe_command %s" % str(ffmpeg_pipe_command)) self.ffmpeg_pipe_subprocess = subprocess.Popen(ffmpeg_pipe_command, stdin=subprocess.PIPE, stdout=console_output)