def run_ffmpeg_command(self): # wrapper for 'ffmpeg-progress-yield' ff = FfmpegProgress(self.cmd, dry_run=self.dry) for progress in ff.run_command_with_progress(): yield progress self.output = ff.stderr
def test_library(self): cmd = [ "ffmpeg", "-i", "test/test.mp4", "-c:v", "libx264", "-vf", "scale=1920x1080", "-preset", "fast", "-f", "null", "/dev/null", ] ff = FfmpegProgress(cmd) for progress in ff.run_command_with_progress(): print(f"{progress}/100")
def _run_ffmpeg_command(self, filter_chains=[], desc=""): """ Run the ffmpeg command to get the quality metrics. The filter chains must be specified manually. 'desc' can be a human readable description for the progress bar. """ if not self.framerate: ref_framerate, dist_framerate = self._get_framerates() else: ref_framerate = self.framerate dist_framerate = self.framerate cmd = [ "ffmpeg", "-nostdin", "-nostats", "-y", "-threads", str(self.threads), "-r", str(ref_framerate), "-i", self.ref, "-r", str(dist_framerate), "-i", self.dist, "-filter_complex", ";".join(filter_chains), "-an", "-f", "null", NUL, ] if self.progress: ff = FfmpegProgress(cmd, self.dry_run) with tqdm(total=100, position=1, desc=desc) as pbar: for progress in ff.run_command_with_progress(): pbar.update(progress - pbar.n) return ff.stderr else: _, stderr = run_command(cmd, self.dry_run, self.verbose) return stderr
def getVmaf(self, log_path=None, model='HD', subsample=1, output_fmt='json', threads=0, print_progress=False, end_sync=False, features=None, cambi_heatmap=False): main = self.main.lastOutputID ref = self.ref.lastOutputID if output_fmt == 'xml': log_fmt = "xml" if log_path == None: log_path = os.path.splitext( self.main.videoSrc)[0] + '_vmaf.xml' else: log_fmt = "json" if log_path == None: log_path = os.path.splitext( self.main.videoSrc)[0] + '_vmaf.json' self.vmafpath = log_path self.vmaf_cambi_heatmap_path = os.path.splitext( self.main.videoSrc)[0] + '_cambi_heatmap' if model == 'HD': model_hd = f'version={HD_MODEL_VERSION}\\\\:name={HD_MODEL_NAME}|version={HD_NEG_MODEL_VERSION}\\\\:name={HD_NEG_MODEL_NAME}|version={HD_PHONE_MODEL_VERSION}\\\\:name={HD_PHONE_MODEL_NAME}\\\\:enable_transform=true' model = model_hd elif model == '4K': model_4k = f'version={_4K_MODEL_VERSION}\\\\:name={_4K_MODEL_NAME}' model = model_4k if threads == 0: threads = os.cpu_count() if end_sync: shortest = 1 else: shortest = 0 if not features: self.vmafFilter = [ f'[{main}][{ref}]libvmaf=log_fmt={log_fmt}:model={model}:n_subsample={subsample}:log_path={log_path}:n_threads={threads}:shortest={shortest}' ] elif features and not cambi_heatmap: self.vmafFilter = [ f'[{main}][{ref}]libvmaf=log_fmt={log_fmt}:model={model}:n_subsample={subsample}:log_path={log_path}:n_threads={threads}:shortest={shortest}:feature={features}' ] elif features and cambi_heatmap: self.vmafFilter = [ f'[{main}][{ref}]libvmaf=log_fmt={log_fmt}:model={model}:n_subsample={subsample}:log_path={log_path}:n_threads={threads}:shortest={shortest}:feature={features}\\\\:heatmaps_path={self.vmaf_cambi_heatmap_path}' ] self._commit() if self.loglevel == "verbose": print(self.cmd, flush=True) if print_progress: cmd_progress = shlex.split(self.cmd) process = FfmpegProgress(cmd_progress) for progress in process.run_command_with_progress(): print(f"progress = {progress}% - ", "\n".join(str(process.stderr).splitlines()[-9:-8]), flush=True) else: process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, shell=True) process.communicate() return process
def get_scenecuts(in_f, threshold=0.3, progress=False, verbose=False): """ Calculate scene cuts with ffmpeg. """ if not (0 <= threshold <= 1): raise RuntimeError("Threshold must be between 0 and 1") temp_dir = tempfile.gettempdir() temp_file_name = os.path.join( temp_dir, next(tempfile._get_candidate_names()) + ".txt") try: cmd = [ "ffmpeg", "-loglevel", "error", "-y", "-i", in_f, "-vf", "select=gte(scene\,0),metadata=print:file=" + temp_file_name, "-an", "-f", "null", "-", ] if verbose: cmd_q = " ".join([shlex.quote(c) for c in cmd]) print("Running ffmpeg command: {}".format(cmd_q), file=sys.stderr) ff = FfmpegProgress(cmd) if progress: with tqdm(total=100, position=1) as pbar: for progress in ff.run_command_with_progress(): pbar.update(progress - pbar.n) else: for _ in ff.run_command_with_progress(): pass lines = [] if os.path.isfile(temp_file_name): with open(temp_file_name, "r") as out_f: lines = out_f.readlines() frames = [] last_frame_info = {} for line in lines: line = line.strip() if line.startswith("frame"): rex = r"frame:(?P<frame>\d+)\s+pts:(?P<pts>[\d\.]+)\s+pts_time:(?P<pts_time>[\d\.]+)" ret = re.match(rex, line) if ret: ret_matches = ret.groupdict() last_frame_info["frame"] = int(ret_matches["frame"]) last_frame_info["pts"] = float(ret_matches["pts"]) last_frame_info["pts_time"] = float( ret_matches["pts_time"]) else: raise RuntimeError("Wrongly formatted line: " + line) continue if line.startswith("lavfi.scene_score"): splits = line.split("=") if len(splits): last_frame_info["score"] = float(splits[1]) else: raise RuntimeError("Wrongly formatted line: " + line) frames.append(last_frame_info) last_frame_info = {} scenecuts = [f for f in frames if f["score"] >= threshold] except Exception as e: raise e finally: if os.path.isfile(temp_file_name): os.remove(temp_file_name) return scenecuts