Skip to content

Commit 25da214

Browse files
committed
Enforcing Python >=3.8, improved logging, updated TODO.
1 parent 91d43b1 commit 25da214

File tree

2 files changed

+42
-29
lines changed

2 files changed

+42
-29
lines changed

compareEncoding.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import sys
99

1010
parser = argparse.ArgumentParser()
11-
parser.add_argument("filename", help="Source filename")
11+
parser.add_argument("filename", help="Source filename (or \"all\" to compare all files which exist in both source/ and hevc/)")
1212
parser.add_argument("num_frames", nargs="?", default=5, type=int, help="Number of comparison frames to generate")
1313
parser.add_argument("-s", "--stack", action="store_true", help="Also create 2-up stacked comparison")
1414
args = parser.parse_args()
@@ -57,12 +57,12 @@
5757
ret,hevc_frame = hevc_file_handle.read()
5858
if args.stack:
5959
comparison_frame = np.vstack((source_frame,hevc_frame))
60-
cv2.imwrite(os.path.join(output_directory, "{number}-2up.png".format(number=frame)), comparison_frame)
61-
cv2.imwrite(os.path.join(output_directory, "{number}-original.png".format(number=frame)), source_frame)
60+
cv2.imwrite(os.path.join(output_directory, "{number}-2up.png".format(number=frame)), comparison_frame, [cv2.IMWRITE_PNG_COMPRESSION, 0])
61+
cv2.imwrite(os.path.join(output_directory, "{number}-source.png".format(number=frame)), source_frame, [cv2.IMWRITE_PNG_COMPRESSION, 0])
6262
cv2.imwrite(os.path.join(output_directory, "{number}-x265.png".format(number=frame)), hevc_frame)
6363

6464
hevc_file_handle.release()
6565

6666
source_file_handle.release()
6767

68-
sys.exit("Done.")
68+
sys.exit("Done.\n")

transcode.py

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,29 @@
1414
1515
TODO:
1616
- convert all string paths into os.path objects
17-
- check for python3.8
17+
- allow comma-separated string for --preset, e.g. medium,slow,slower, map to list
18+
- add --matrix option to create default, best, small, best+small variants
19+
- add compression ratio / space saved to log + screen output
1820
1921
"""
2022

23+
# Check for Python 3.8 (required for shlex usage)
24+
if not (sys.version_info[0] >= 3 and sys.version_info[1] >= 8):
25+
sys.exit("FATAL: Requires Python3.8 or newer.")
26+
2127
class Session():
2228
class Settings:
2329
class RF:
24-
SD = 21
25-
HD = 22
26-
FHD = 23
27-
UHD = 26
30+
SD = 18
31+
HD = 20
32+
FHD = 21
33+
UHD = 24
2834

2935
class ENCOPTS:
3036
SD = "ctu=32:qg-size=16"
3137
HD = "ctu=32:qg-size=32"
3238
FHD = "ctu=64:qg-size=64"
33-
ENCOPTS = "ctu=64:qg-size=64"
39+
UHD = "ctu=64:qg-size=64"
3440

3541
def __init__(self, file):
3642
signal.signal(signal.SIGINT, self.signal_handler)
@@ -41,8 +47,8 @@ def __init__(self, file):
4147
metadata = json.loads(metadata)["streams"][0]
4248

4349
# Populate metadata-based attributes
44-
self.paths = {"source": file}
45-
self.source = {"height": int(metadata["height"]), "width": int(metadata["width"]), "duration": float(metadata["duration"]), "filename": os.path.splitext(os.path.relpath(self.paths["source"], "source"))[0], "filesize": os.path.getsize(self.paths["source"]), "bitrate": int(metadata["bit_rate"]), "frames": int(metadata["nb_frames"]), "codec": metadata["codec_name"]}
50+
self.path = {"source": file}
51+
self.source = {"height": int(metadata["height"]), "width": int(metadata["width"]), "duration": float(metadata["duration"]), "filename": os.path.splitext(os.path.relpath(self.path["source"], "source"))[0], "filesize": os.path.getsize(self.path["source"]), "bitrate": int(metadata["bit_rate"]), "frames": int(metadata["nb_frames"]), "codec": metadata["codec_name"]}
4652
height = self.source["height"]
4753
if height < 720:
4854
resolution = "SD"
@@ -71,26 +77,25 @@ def __init__(self, file):
7177
self.file_decorator += "_Small"
7278
if args.preset:
7379
self.file_decorator += "_{preset}".format(preset=args.preset.capitalize())
74-
self.paths["output"] = "hevc/" + self.source["filename"] + self.file_decorator + ".mp4"
75-
self.paths["log"] = "performance/" + self.source["filename"] + self.file_decorator + ".log"
80+
self.path["output"] = "hevc/" + self.source["filename"] + self.file_decorator + ".mp4"
81+
self.path["log"] = "performance/" + self.source["filename"] + self.file_decorator + ".log"
7682

7783
# Build HandBrakeCLI command
78-
self.args = "HandBrakeCLI --encoder-preset {encoder_preset} --preset-import-file presets.json --preset {preset_name} --quality {quality} --encopts {encopts} --input {source_path} --output {output_path}".format(encoder_preset=self.encoder_preset, preset_name=self.preset_name, quality=str(self.encoder_quality), encopts=self.encoder_options, source_path=self.paths["source"], output_path=self.paths["output"])
84+
self.args = "HandBrakeCLI --encoder-preset {encoder_preset} --preset-import-file presets.json --preset {preset_name} --quality {quality} --encopts {encopts} --input {source_path} --output {output_path}".format(encoder_preset=self.encoder_preset, preset_name=self.preset_name, quality=str(self.encoder_quality), encopts=self.encoder_options, source_path=self.path["source"], output_path=self.path["output"])
7985

80-
# Validate and finish
86+
# Verify no attributes are None
8187
self.validate()
82-
self.summarize()
8388

8489
def validate(self):
8590
""" Verifies that no session attributes are null
8691
"""
8792
if any(value is None for attribute, value in self.__dict__.items()):
88-
sys.exit("FATAL: Session.validate(): found null attribute for " + self.paths["source"])
93+
sys.exit("FATAL: Session.validate(): found null attribute for " + self.path["source"])
8994

9095
def summarize(self):
9196
""" Summarize transcode session before starting
9297
"""
93-
print("{date}: {source}:".format(date=str(datetime.now()), source=self.paths["source"]))
98+
print("{date}: {source}:".format(date=str(datetime.now()), source=self.path["source"]))
9499
pprint(vars(self))
95100
print()
96101

@@ -122,7 +127,7 @@ def signal_handler(self, sig, frame):
122127
def log(self, elapsed_time, fps):
123128
""" Summarizes transcode session for screen and log
124129
"""
125-
with open(self.paths["log"], "w") as logfile:
130+
with open(self.path["log"], "w") as logfile:
126131
summary = str(elapsed_time) + "\n" + str(fps) + " fps"
127132
logfile.write(summary + "\n\n" + session.args + "\n\n")
128133
pprint(vars(self), logfile)
@@ -131,11 +136,11 @@ def log(self, elapsed_time, fps):
131136
def cleanup(self):
132137
""" Always deletes output file, deletes log if --delete is passed from command-line
133138
"""
134-
if os.path.exists(self.paths["output"]):
135-
os.remove(self.paths["output"])
139+
if os.path.exists(self.path["output"]):
140+
os.remove(self.path["output"])
136141
if args.delete:
137-
if os.path.exists(self.paths["log"]):
138-
os.remove(self.paths["log"])
142+
if os.path.exists(self.path["log"]):
143+
os.remove(self.path["log"])
139144

140145
# Define command-line arguments
141146
parser = argparse.ArgumentParser()
@@ -187,26 +192,34 @@ def cleanup(self):
187192

188193
# Do the thing
189194
start_time = datetime.now()
195+
skipped_files = []
190196
print("\n{date}: Starting transcode session for {source_files}\n".format(date=str(datetime.now()), source_files=str(source_files)))
191197
for file in source_files:
192198
session = Session(file)
193-
if not os.path.exists(session.paths["output"]):
199+
if not os.path.exists(session.path["output"]):
200+
session.summarize()
194201
print(session.args + "\n")
195202
session_start_time = datetime.now()
196-
transcode = subprocess.Popen(shlex.split(session.args, posix=False))
203+
transcode = subprocess.Popen(shlex.split(session.args, posix=False)) # Posix=False to escape double-quotes in arguments
197204
transcode.wait()
198205
session_end_time = datetime.now()
199206
session_elapsed_time = session_end_time - session_start_time
200207
fps = session.source["frames"] / session_elapsed_time.seconds
201-
print("\n{date}: Finished {output_file}".format(date=str(session_end_time), output_file=session.paths["output"]))
208+
print("\n{date}: Finished {output_file}".format(date=str(session_end_time), output_file=session.path["output"]))
202209
session.log(session_elapsed_time, fps)
210+
print("\n\n\n\n\n")
203211
else:
204-
print(session.paths["output"], "already exists, skipping.")
212+
skipped_files.append(file)
205213
if args.delete:
206214
session.cleanup()
207-
print("\n\n\n\n\n")
208215

209216
end_time = datetime.now()
210217
elapsed_time = end_time - start_time
211218

219+
if len(skipped_files) > 0:
220+
print("Skipped:")
221+
for file in skipped_files:
222+
print(file)
223+
print()
224+
212225
sys.exit("{date}: Finished after {elapsed_time}.\n".format(date=str(datetime.now()), elapsed_time=elapsed_time))

0 commit comments

Comments
 (0)