예제 #1
0
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()
예제 #2
0
    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)
예제 #3
0
    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)
예제 #4
0
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
예제 #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:
    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()
예제 #6
0
    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
예제 #7
0
    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
예제 #8
0
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)
예제 #9
0
    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
예제 #10
0
파일: ffmpeg.py 프로젝트: postcc/dandere2x
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()
예제 #11
0
    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)
예제 #12
0
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)