def create_select_chunk(args: Args, index: int, src_path: Path, frame_start: int, frame_end: int) -> Chunk: """ Creates a chunk using ffmpeg's select filter :param args: the Args :param src_path: the path of the entire unchunked source file :param index: the index of the chunk :param frame_start: frame that this chunk should start on (0-based, inclusive) :param frame_end: frame that this chunk should end on (0-based, exclusive) :return: a Chunk """ assert frame_end > frame_start, "Can't make a chunk with <= 0 frames!" frames = frame_end - frame_start frame_end -= 1 # the frame end boundary is actually a frame that should be included in the next chunk ffmpeg_gen_cmd = [ 'ffmpeg', '-y', '-hide_banner', '-loglevel', 'error', '-i', src_path.as_posix(), '-vf', f'select=between(n\\,{frame_start}\\,{frame_end}),setpts=PTS-STARTPTS', *args.pix_format, '-bufsize', '50000K', '-f', 'yuv4mpegpipe', '-' ] extension = ENCODERS[args.encoder].output_extension size = frames # use the number of frames to prioritize which chunks encode first, since we don't have file size chunk = Chunk(args.temp, index, ffmpeg_gen_cmd, extension, size, frames) return chunk
def plot_vmaf(source: Path, encoded: Path, args, model, vmaf_res): """ Making VMAF plot after encode is done """ print('Calculating Vmaf...\r', end='') fl_path = encoded.with_name(f'{encoded.stem}_vmaflog').with_suffix(".json") # call_vmaf takes a chunk, so make a chunk of the entire source ffmpeg_gen_cmd = [ 'ffmpeg', '-y', '-hide_banner', '-loglevel', 'error', '-i', source.as_posix(), *args.pix_format, '-f', 'yuv4mpegpipe', '-' ] input_chunk = Chunk(args.temp, 0, ffmpeg_gen_cmd, '', 0, 0) scores = call_vmaf(input_chunk, encoded, 0, model, vmaf_res, fl_path=fl_path) if not scores.exists(): print( f'Vmaf calculation failed for chunks:\n {source.name} {encoded.stem}' ) sys.exit() file_path = encoded.with_name(f'{encoded.stem}_plot').with_suffix('.png') plot_vmaf_score_file(scores, file_path)
def create_vsffms2_chunk(args: Args, index: int, load_script: Path, frame_start: int, frame_end: int) -> Chunk: """ Creates a chunk using vspipe and ffms2 :param args: the Args :param load_script: the path to the .vpy script for vspipe :param index: the index of the chunk :param frame_start: frame that this chunk should start on (0-based, inclusive) :param frame_end: frame that this chunk should end on (0-based, exclusive) :return: a Chunk """ assert frame_end > frame_start, "Can't make a chunk with <= 0 frames!" frames = frame_end - frame_start frame_end -= 1 # the frame end boundary is actually a frame that should be included in the next chunk ffmpeg_gen_cmd = [ 'vspipe', load_script.as_posix(), '-y', '-', '-s', str(frame_start), '-e', str(frame_end) ] extension = ENCODERS[args.encoder].output_extension size = frames # use the number of frames to prioritize which chunks encode first, since we don't have file size chunk = Chunk(args.temp, index, ffmpeg_gen_cmd, extension, size, frames) return chunk
def target_vmaf_routine(args: Args, chunk: Chunk): """ Applies target vmaf to this chunk. Determines what the cq value should be and sets the vmaf_target_cq for this chunk :param args: the Args :param chunk: the Chunk :return: None """ chunk.vmaf_target_cq = target_vmaf(chunk, args)
def per_frame_target_quality_routine(args: Project, chunk: Chunk): """ Applies per_shot_target_quality to this chunk. Determines what the cq value should be and sets the per_shot_target_quality_cq for this chunk :param args: the Project :param chunk: the Chunk :return: None """ chunk.per_frame_target_quality_cq = per_frame_target_quality(chunk, args)
def read_chunk_queue(temp: Path) -> List[Chunk]: """ Reads the chunk queue from the chunks.json file :param temp: the temp directory :return: the chunk queue """ with open(temp / 'chunks.json', 'r') as file: chunk_dicts = json.load(file) return [Chunk.create_from_dict(cd, temp) for cd in chunk_dicts]
def create_chunk_from_segment(args: Args, index: int, file: Path) -> Chunk: """ Creates a Chunk object from a segment file generated by ffmpeg :param args: the Args :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(), *args.pix_format, '-bufsize', '50000K', '-f', 'yuv4mpegpipe', '-' ] file_size = file.stat().st_size frames = frame_probe(file) extension = ENCODERS[args.encoder].output_extension chunk = Chunk(args.temp, index, ffmpeg_gen_cmd, extension, file_size, frames) return chunk