feat(encode-comparison): encode middle clip across CRF values
This commit is contained in:
Executable
+77
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3.11
|
||||
import argparse
|
||||
import logging
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Encode middle 1-min slice of video with multiple CRF values.",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument("video", type=Path, help="Input video file")
|
||||
parser.add_argument("--codec", choices=["x264", "x265"], default="x265", help="Codec to use")
|
||||
parser.add_argument("--crf", nargs="+", type=int, default=[15, 20, 25, 30, 35, 40], help="CRF values")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def read_video_duration(video_path: Path) -> float:
|
||||
cmd = [
|
||||
"ffprobe",
|
||||
"-v",
|
||||
"error",
|
||||
"-show_entries",
|
||||
"format=duration",
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
str(video_path),
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
||||
return float(result.stdout.strip())
|
||||
|
||||
|
||||
def encode_clip(clip_path: Path, codec: str, crf: int, out_path: Path) -> Path:
|
||||
# clip_path is actually the input video, we encode the middle slice on the fly
|
||||
total_duration = read_video_duration(clip_path)
|
||||
slice_duration = 60
|
||||
start = max(0, int(total_duration // 2 - slice_duration // 2))
|
||||
if codec == "x264":
|
||||
lib = "h264_videotoolbox"
|
||||
else:
|
||||
lib = "hevc_videotoolbox"
|
||||
cmd = [
|
||||
"ffmpeg",
|
||||
"-y",
|
||||
"-ss",
|
||||
str(start),
|
||||
"-t",
|
||||
str(slice_duration),
|
||||
"-i",
|
||||
str(clip_path),
|
||||
"-c:v",
|
||||
lib,
|
||||
"-q:v",
|
||||
str(crf),
|
||||
"-preset",
|
||||
"medium",
|
||||
"-c:a",
|
||||
"copy",
|
||||
str(out_path),
|
||||
]
|
||||
logging.info(f"Encoding {out_path.name} with {lib} q:v={crf} (hwaccel) from middle slice")
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s")
|
||||
args = parse_args()
|
||||
outdir = args.video.parent
|
||||
outdir.mkdir(parents=True, exist_ok=True)
|
||||
for crf in args.crf:
|
||||
out_path = outdir / f"{args.video.stem}.{args.codec}_crf{crf}.mp4"
|
||||
encode_clip(clip_path=args.video, codec=args.codec, crf=crf, out_path=out_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user