def create_video_queue_vs(project: Project, split_locations: List[int], script: str) -> List[Chunk]: """ Create a list of chunks using vspipe and ffms2 for frame accurate seeking :param project: the Project :param split_locations: a list of frames to split on :param script: source filter script to use with vspipe (ignored with vs input) :return: A list of chunks """ # add first frame and last frame last_frame = project.get_frames() split_locs_fl = [0] + split_locations + [last_frame] # pair up adjacent members of this list ex: [0, 10, 20, 30] -> [(0, 10), (10, 20), (20, 30)] chunk_boundaries = zip(split_locs_fl, split_locs_fl[1:]) source_file = project.input.absolute().as_posix() vs_script = project.input if not project.is_vs: # create a vapoursynth script that will load the source with ffms2 load_script = project.temp / 'split' / 'loadscript.vpy' cache_file = (project.temp / 'split' / 'ffms2cache.ffindex').absolute().as_posix() with open(load_script, 'w+') as file: file.write(script.format(source_file, cache_file)) vs_script = load_script chunk_queue = [ create_vs_chunk(project, index, vs_script, *cb) for index, cb in enumerate(chunk_boundaries) ] return chunk_queue
def create_video_queue_vs(project: Project, split_locations: List[int]) -> List[Chunk]: """ Create a list of chunks using vspipe and ffms2 for frame accurate seeking :param project: the Project :param split_locations: a list of frames to split on :param script: source filter script to use with vspipe (ignored with vs input) :return: A list of chunks """ # add first frame and last frame last_frame = project.get_frames() split_locs_fl = [0] + split_locations + [last_frame] # pair up adjacent members of this list ex: [0, 10, 20, 30] -> [(0, 10), (10, 20), (20, 30)] chunk_boundaries = zip(split_locs_fl, split_locs_fl[1:]) source_file = project.input.absolute().as_posix() if project.is_vs: vs_script = project.input else: vs_script = create_vs_file(project.temp, source_file, project.chunk_method) chunk_queue = [ create_vs_chunk(project, index, vs_script, *cb) for index, cb in enumerate(chunk_boundaries) ] return chunk_queue
def create_chunk_from_segment(project: Project, index: int, file: Path) -> Chunk: """ Creates a Chunk object from a segment file generated by ffmpeg :param project: the Project :param index: the index of the chunk :param file: the segmented file :return: A Chunk """ ffmpeg_gen_cmd = [ "ffmpeg", "-y", "-hide_banner", "-loglevel", "error", "-i", file.as_posix(), *project.pix_format, "-f", "yuv4mpegpipe", "-", ] file_size = file.stat().st_size frames = project.get_frames() extension = ENCODERS[project.encoder].output_extension chunk = Chunk(project.temp, index, ffmpeg_gen_cmd, extension, file_size, frames) return chunk
def startup_check(project: Project): """ Performing essential checks at startup_check Set constant values """ if sys.version_info < (3, 6): print("Python 3.6+ required") sys.exit() if sys.platform == "linux": def restore_term(): os.system("stty sane") atexit.register(restore_term) if project.encoder not in ["rav1e", "aom", "svt_av1", "vpx"] and project.output_ivf: print(".ivf only supports VP8, VP9, and AV1") sys.exit(1) if not project.chunk_method: project.select_best_chunking_method() project.is_vs = is_vapoursynth(project.input[0]) if project.is_vs: project.chunk_method = "vs_ffms2" project.check_exes() set_target_quality(project) setup_encoder(project) project.audio_params = shlex.split(project.audio_params) project.ffmpeg = shlex.split(project.ffmpeg) project.pix_format = ["-strict", "-1", "-pix_fmt", project.pix_format] project.ffmpeg_pipe = [ *project.ffmpeg, *project.pix_format, "-f", "yuv4mpegpipe", "-", ]
def setup_encoder(project: Project): """ Setup encoder params and passes :param project: the Project """ encoder = ENCODERS[project.encoder] # validate encoder settings settings_valid, error_msg = encoder.is_valid(project) if not settings_valid: print(error_msg) terminate() if project.passes is None: project.passes = encoder.default_passes project.video_params = encoder.default_args if project.video_params is None \ else shlex.split(project.video_params) validate_inputs(project)
def create_video_queue_select(project: Project, split_locations: List[int]) -> List[Chunk]: """ Create a list of chunks using the select filter :param project: the Project :param split_locations: a list of frames to split on :return: A list of chunks """ # add first frame and last frame last_frame = project.get_frames() split_locs_fl = [0] + split_locations + [last_frame] # pair up adjacent members of this list ex: [0, 10, 20, 30] -> [(0, 10), (10, 20), (20, 30)] chunk_boundaries = zip(split_locs_fl, split_locs_fl[1:]) chunk_queue = [ create_select_chunk(project, index, project.input, *cb) for index, cb in enumerate(chunk_boundaries) ] return chunk_queue
def create_video_queue_hybrid(project: Project, split_locations: List[int]) -> List[Chunk]: """ Create list of chunks using hybrid segment-select approach :param project: the Project :param split_locations: a list of frames to split on :return: A list of chunks """ keyframes = get_keyframes(str(project.input.resolve())) end = [project.get_frames()] splits = [0] + split_locations + end segments_list = list(zip(splits, splits[1:])) to_split = [x for x in keyframes if x in splits] segments = [] # Make segments log("Segmenting Video") segment(str(project.input.resolve()), str(project.temp.resolve()), to_split[1:]) log("Segment Done") source_path = project.temp / "split" queue_files = [x for x in source_path.iterdir() if x.suffix == ".mkv"] queue_files.sort(key=lambda p: p.stem) kf_list = list(zip(to_split, to_split[1:] + end)) for f, (x, y) in zip(queue_files, kf_list): to_add = [(f, [s[0] - x, s[1] - x]) for s in segments_list if s[0] >= x and s[1] <= y and s[0] - x < s[1] - x] segments.extend(to_add) chunk_queue = [ create_select_chunk(project, index, file, *cb) for index, (file, cb) in enumerate(segments) ] return chunk_queue
def create_chunk_from_segment(project: Project, index: int, file: Path) -> Chunk: """ Creates a Chunk object from a segment file generated by ffmpeg :param project: the Project :param index: the index of the chunk :param file: the segmented file :return: A Chunk """ ffmpeg_gen_cmd = [ 'ffmpeg', '-y', '-hide_banner', '-loglevel', 'error', '-i', file.as_posix(), *project.pix_format, '-color_range', '0', '-f', 'yuv4mpegpipe', '-' ] file_size = file.stat().st_size frames = project.get_frames() extension = ENCODERS[project.encoder].output_extension chunk = Chunk(project.temp, index, ffmpeg_gen_cmd, extension, file_size, frames) return chunk
def startup_check(project: Project): """ Performing essential checks at startup_check Set constant values """ if sys.version_info < (3, 6): print('Python 3.6+ required') sys.exit() if sys.platform == 'linux': def restore_term(): os.system("stty sane") atexit.register(restore_term) if not project.chunk_method: project.select_best_chunking_method() # project.is_vs = is_vapoursynth(project.input) if project.is_vs: project.chunk_method = 'vs_ffms2' project.check_exes() set_target_quality(project) if project.reuse_first_pass and project.encoder != 'aom' and project.split_method != 'aom_keyframes': print('Reusing the first pass is only supported with \ the aom encoder and aom_keyframes split method.') terminate() setup_encoder(project) # No check because vvc if project.encoder == 'vvc': project.no_check = True if project.encoder == 'svt_vp9' and project.passes == 2: print("Implicitly changing 2 pass svt-vp9 to 1 pass\n2 pass svt-vp9 isn't supported") project.passes = 1 project.audio_params = shlex.split(project.audio_params) project.ffmpeg = shlex.split(project.ffmpeg) project.pix_format = ['-strict', '-1', '-pix_fmt', project.pix_format] project.ffmpeg_pipe = [*project.ffmpeg, *project.pix_format,'-color_range', '0', '-f', 'yuv4mpegpipe', '-']
def startup_check(project: Project): """ Performing essential checks at startup_check Set constant values """ if sys.version_info < (3, 6): print("Python 3.6+ required") sys.exit() if sys.platform == "linux": def restore_term(): os.system("stty sane") atexit.register(restore_term) if not project.chunk_method: project.select_best_chunking_method() project.is_vs = is_vapoursynth(project.input[0]) if project.is_vs: project.chunk_method = "vs_ffms2" project.check_exes() set_target_quality(project) if (project.reuse_first_pass and project.encoder != "aom" and project.split_method != "aom_keyframes"): print("Reusing the first pass is only supported with \ the aom encoder and aom_keyframes split method.") terminate() setup_encoder(project) # No check because vvc if project.encoder == "vvc": project.no_check = True if project.encoder == "svt_vp9" and project.passes == 2: print( "Implicitly changing 2 pass svt-vp9 to 1 pass\n2 pass svt-vp9 isn't supported" ) project.passes = 1 project.audio_params = shlex.split(project.audio_params) project.ffmpeg = shlex.split(project.ffmpeg) project.pix_format = ["-strict", "-1", "-pix_fmt", project.pix_format] project.ffmpeg_pipe = [ *project.ffmpeg, *project.pix_format, "-f", "yuv4mpegpipe", "-", ]
def get_av1an_proj(args): return Project(args)