android_external_ffmpeg/pi-util/ffperf.py
2025-06-24 22:46:48 -05:00

140 lines
4.4 KiB
Python
Executable file

#!/usr/bin/env python3
import shlex
import time
import string
import os
import tempfile
import subprocess
import re
import argparse
import sys
import csv
from stat import *
class tstats:
close_threshold = 0.01
def __init__(self, stats_dict=None):
if stats_dict != None:
self.name = stats_dict["name"]
self.elapsed = float(stats_dict["elapsed"])
self.user = float(stats_dict["user"])
self.sys = float(stats_dict["sys"])
def times_str(self):
ctime = self.sys + self.user
return "time=%6.2f, cpu=%6.2f (%4.2f%%)" % (self.elapsed, ctime, (ctime * 100.0) / self.elapsed)
def dict(self):
return {"name":self.name, "elapsed":self.elapsed, "user":self.user, "sys":self.sys}
def is_close(self, other):
return abs(self.elapsed - other.elapsed) / self.elapsed < self.close_threshold
def __lt__(self, other):
return self.elapsed < other.elapsed
def __gt__(self, other):
return self.elapsed > other.elapsed
def time_file(name, prefix, args):
cmdargs = [args.ffmpeg]
for x in args.args :
if x == '{INPUT}':
cmdargs.append(prefix + name)
elif x == '{NULL}':
cmdargs.append(os.devnull)
else:
cmdargs.append(x)
stats = tstats()
stats.name = name
start_time = time.clock_gettime(time.CLOCK_MONOTONIC);
cproc = subprocess.Popen(cmdargs, bufsize=-1, stdout=flog, stderr=flog);
pinfo = os.wait4(cproc.pid, 0)
end_time = time.clock_gettime(time.CLOCK_MONOTONIC);
stats.elapsed = end_time - start_time
stats.user = pinfo[2].ru_utime
stats.sys = pinfo[2].ru_stime
return stats
def common_prefix(s1, s2):
for i in range(min(len(s1),len(s2))):
if s1[i] != s2[i]:
return s1[:i]
return s1[:i+1]
def main():
global flog
argp = argparse.ArgumentParser(description="FFmpeg performance tester", epilog="""
To blank the screen before starting use "xdg-screensaver activate"
(For some reason this doesn't seem to work from within python).
""")
argp.add_argument("streams", nargs='*')
argp.add_argument("--args", default='-t 30 -i {INPUT} -f null {NULL}', help="""
ffmpeg arguments, default='-t 30 -i {INPUT} -f null {NULL}';
{INPUT} is replaced by current inputfile path;
{NULL} is replaced by the system null device""")
argp.add_argument("--csv_out", default="ffperf_out.csv", help="CSV output filename")
argp.add_argument("--csv_in", help="CSV input filename")
argp.add_argument("--prefix", help="Filename prefix (include terminal '/' if a directory).")
argp.add_argument("--repeat", default=3, type=int, help="Run repeat count")
argp.add_argument("--ffmpeg", default="./ffmpeg", help="FFmpeg executable")
args = argp.parse_args()
args.args = shlex.split(args.args)
csv_out = csv.DictWriter(open(args.csv_out, 'w', newline=''), ["name", "elapsed", "user", "sys"])
csv_out.writeheader()
stats_in = {}
if args.csv_in != None:
with open(args.csv_in, 'r', newline='') as f_in:
stats_in = {x["name"]:tstats(x) for x in csv.DictReader(f_in)}
flog = open(os.path.join(tempfile.gettempdir(), "ffperf.log"), "wt")
streams = args.streams
if not streams:
if not stats_in:
print ("No source streams specified")
return 1
prefix = "" if args.prefix == None else args.prefix
streams = [k for k in stats_in]
elif args.prefix != None:
prefix = args.prefix
else:
prefix = streams[0]
for f in streams[1:]:
prefix = common_prefix(prefix, f)
pp = prefix.rpartition(os.sep)
prefix = pp[0] + pp[1]
streams = [s[len(prefix):] for s in streams]
for f in sorted(streams, key=lambda x : "~" * x.count(os.sep) + x.lower()):
print ("====", f)
t0 = tstats({"name":f, "elapsed":999, "user":999, "sys":999})
for i in range(args.repeat):
t = tstats.time_file(f, prefix, args)
print ("...", t.times_str())
if t0 > t:
t0 = t
if t0.name in stats_in:
pstat = stats_in[t0.name]
print("---" if pstat.is_close(t0) else "<<<" if t0 < pstat else ">>>", pstat.times_str())
csv_out.writerow(t0.dict())
print ()
return 0
if __name__ == '__main__':
exit(main())