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