Esempio n. 1
0
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("root")
    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)
    def _check_and_fix_resolution(input_file: str, block_size: int, output_options_original: dict) -> dict:
        """
        Returns a dictionary containing the output settings, taking into consideration if the video needs to be resized,
        and if it does, changes the pipe_video commands to include dar.
        """
        from dandere2x.dandere2xlib.utils.yaml_utils import load_executable_paths_yaml
        from dandere2x.dandere2xlib.wrappers.ffmpeg.ffmpeg import append_resize_filter_to_pre_process, \
            append_dar_filter_to_pipe_process
        from dandere2x.dandere2xlib.wrappers.ffmpeg.videosettings import VideoSettings
        import copy

        def valid_input_resolution(width: int, height: int, block_size: int):
            return width % block_size == 0 and height % block_size == 0

        new_output_options = copy.copy(output_options_original)

        # get meta-data from the video to do pre-processing
        ffprobe_path = load_executable_paths_yaml()['ffprobe']
        video_settings = VideoSettings(ffprobe_path, input_file)
        width, height = video_settings.width, video_settings.height

        if not valid_input_resolution(width=width, height=height, block_size=block_size):
            append_resize_filter_to_pre_process(output_options=new_output_options,
                                                width=width,
                                                height=height,
                                                block_size=block_size)
            append_dar_filter_to_pipe_process(output_options=new_output_options,
                                              width=width,
                                              height=height)

        return new_output_options
Esempio n. 3
0
def divide_and_reencode_video(ffmpeg_path: str, ffprobe_path: str,
                              input_video: str, output_options: dict,
                              divide: int, output_dir: str):
    from dandere2x.dandere2xlib.wrappers.ffmpeg.videosettings import VideoSettings
    """
    
    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,
                               ffmpeg_dir=ffmpeg_path,
                               video_file=input_video).frame_rate

    execute = [ffmpeg_path]

    hw_accel = output_options["ffmpeg"]["pre_process_video"]["-hwaccel"]
    if hw_accel is not None:
        execute.append("-hwaccel")
        execute.append(hw_accel)

    execute.extend([
        "-i", input_video, "-f", "segment", "-segment_time",
        str(ratio), "-c", "copy"
    ])

    # 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
Esempio n. 4
0
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()
Esempio n. 5
0
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()
Esempio n. 6
0
    def __init__(self, service_request: Dandere2xServiceRequest):
        """

        Creates struct-like object that serves as a set of constants and directories dandere2x will use. Once this is
        instantiated, it's to be treated as 'effectively final' meaning that none of the variables will
        change after they're declared.

        Most dandere2x-core functions will require a Dandere2xServiceContext object in order for it to run.

        Args:
            service_request: A service_request, which may be produced by the program or the user.
        """

        self.service_request = service_request

        # Directories and Paths
        self.input_frames_dir = os.path.join(service_request.workspace,
                                             "inputs") + os.path.sep
        self.noised_input_frames_dir = os.path.join(
            service_request.workspace, "noised_inputs") + os.path.sep
        self.residual_images_dir = os.path.join(
            service_request.workspace, "residual_images") + os.path.sep
        self.residual_upscaled_dir = os.path.join(
            service_request.workspace, "residual_upscaled") + os.path.sep
        self.residual_data_dir = os.path.join(service_request.workspace,
                                              "residual_data") + os.path.sep
        self.pframe_data_dir = os.path.join(service_request.workspace,
                                            "pframe_data") + os.path.sep
        self.merged_dir = os.path.join(service_request.workspace,
                                       "merged") + os.path.sep
        self.fade_data_dir = os.path.join(service_request.workspace,
                                          "fade_data") + os.path.sep
        self.debug_dir = os.path.join(service_request.workspace,
                                      "debug") + os.path.sep
        self.console_output_dir = os.path.join(service_request.workspace,
                                               "console_output") + os.path.sep
        self.compressed_static_dir = os.path.join(
            service_request.workspace, "compressed_static") + os.path.sep
        self.encoded_dir = os.path.join(service_request.workspace,
                                        "encoded") + os.path.sep
        self.temp_image_folder = os.path.join(
            service_request.workspace, "temp_image_folder") + os.path.sep
        self.log_dir = os.path.join(service_request.workspace,
                                    "log_dir") + os.path.sep

        self.directories = {
            self.input_frames_dir, self.noised_input_frames_dir,
            self.residual_images_dir, self.residual_upscaled_dir,
            self.merged_dir, self.residual_data_dir, self.pframe_data_dir,
            self.debug_dir, self.console_output_dir,
            self.compressed_static_dir, self.fade_data_dir, self.encoded_dir,
            self.temp_image_folder, self.log_dir
        }

        ffprobe_path = load_executable_paths_yaml()['ffprobe']
        ffmpeg_path = load_executable_paths_yaml()['ffmpeg']
        video_settings = VideoSettings(
            ffprobe_dir=ffprobe_path,
            ffmpeg_dir=ffmpeg_path,
            video_file=self.service_request.input_file)
        self.video_settings = video_settings
        self.width, self.height = video_settings.width, video_settings.height
        self.frame_count = video_settings.frame_count
        self.frame_rate = video_settings.frame_rate

        # todo static-ish settings < add to a yaml somewhere >
        self.bleed = self.service_request.output_options["dandere2x"]["bleed"]
        self.temp_image = self.temp_image_folder + "tempimage.jpg"
        self.debug = False
        self.step_size = 4
        self.max_frames_ahead = 100

        # Dandere2xCPP
        self.dandere2x_cpp_block_matching_arg = self.service_request.output_options[
            "dandere2x_cpp"]["block_matching_arg"]
        self.dandere2x_cpp_evaluator_arg = self.service_request.output_options[
            "dandere2x_cpp"]["evaluator_arg"]