From 4e63e41a0fb939647ab392086727779d4a41ba36 Mon Sep 17 00:00:00 2001 From: Tiger Ren Date: Wed, 2 Sep 2026 23:13:49 +0800 Subject: [PATCH] add hevc nvenc preset and batch compress scripts - hevc_nvenc_1080p.json: 1080p HEVC NVENC preset (slow, 1850k VBR, 160k AAC) - hevc_nvenc_1080p_v2.json: same with decomb off for progressive sources - compress_hevc.py: batch folder compression with duration-based bitrate - compress_hevc_v2.py: adds NVDEC hw decode and optional -j 2 parallel mode - hevc_nvenc_1080p.md: preset usage doc with bitrate sizing table --- compress_hevc.py | 149 +++++++++++++++++++++++++++++ compress_hevc_v2.py | 200 +++++++++++++++++++++++++++++++++++++++ hevc_nvenc_1080p.json | 112 ++++++++++++++++++++++ hevc_nvenc_1080p.md | 73 ++++++++++++++ hevc_nvenc_1080p_v2.json | 112 ++++++++++++++++++++++ 5 files changed, 646 insertions(+) create mode 100644 compress_hevc.py create mode 100644 compress_hevc_v2.py create mode 100644 hevc_nvenc_1080p.json create mode 100644 hevc_nvenc_1080p.md create mode 100644 hevc_nvenc_1080p_v2.json diff --git a/compress_hevc.py b/compress_hevc.py new file mode 100644 index 0000000..64e64b2 --- /dev/null +++ b/compress_hevc.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +"""Batch-compress every video in a folder to HEVC using the "1080P HEVC NVENC" +HandBrake preset (hevc_nvenc_1080p.json, must sit next to this script). + +Drop videos into the folder, run the script, collect the *_hevc.mp4 outputs: + + python compress_hevc.py # uses E:\\Media\\Compress-Temp + python compress_hevc.py D:\\some\\folder # any other folder + python compress_hevc.py --target-gb 3.0 # change target size (default 2.5) + python compress_hevc.py --dry-run # show what would run, encode nothing + +For each file the script probes the duration with ffprobe and derives the +average video bitrate needed to land near the target size, so a 1-hour clip +and a 5-hour movie both come out roughly the same size. Files that are +already at/below the target size are skipped, as are *_hevc.mp4 outputs and +files whose output already exists. Encodes run sequentially (NVENC has a +single hardware encoder, so parallelism buys nothing). +""" + +import argparse +import shutil +import subprocess +import sys +from pathlib import Path + +SCRIPT_DIR = Path(__file__).resolve().parent +PRESET_FILE = SCRIPT_DIR / "hevc_nvenc_1080p.json" +PRESET_NAME = "1080P HEVC NVENC" + +DEFAULT_FOLDER = r"E:\Media\Compress-Temp" +VIDEO_EXTS = {".mp4", ".mkv", ".avi", ".mov", ".m4v", ".ts", ".wmv"} +OUTPUT_SUFFIX = "_hevc" + +AUDIO_KBPS = 160 # audio bitrate set by the preset +OVERSHOOT = 1.09 # NVENC delivers ~9% above the requested avg bitrate +MIN_VIDEO_KBPS = 800 # below this, 1080p HEVC falls apart visibly +MAX_VIDEO_KBPS = 8000 # no point going higher for re-compression + + +def find_tool(name, fallback): + path = shutil.which(name) + if path: + return path + if Path(fallback).exists(): + return fallback + sys.exit(f"error: '{name}' not found on PATH or at {fallback}") + + +def probe_duration(ffprobe, path): + out = subprocess.run( + [ffprobe, "-v", "error", "-show_entries", "format=duration", + "-of", "default=noprint_wrappers=1:nokey=1", str(path)], + capture_output=True, text=True, + ) + if out.returncode != 0: + raise RuntimeError(f"ffprobe failed for {path}: {out.stderr.strip()}") + return float(out.stdout.strip()) + + +def calc_video_bitrate(duration_s, target_bytes): + """Requested (-b) video kbps to land near target_bytes, given NVENC overshoot.""" + total_kbps = target_bytes * 8 / 1000 / duration_s + video_kbps = (total_kbps - AUDIO_KBPS) / OVERSHOOT + return int(round(max(MIN_VIDEO_KBPS, min(MAX_VIDEO_KBPS, video_kbps)))) + + +def fmt_gib(nbytes): + return f"{nbytes / 1024**3:.2f} GiB" + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("folder", nargs="?", default=DEFAULT_FOLDER, + help=f"folder to scan (default: {DEFAULT_FOLDER})") + parser.add_argument("--target-gb", type=float, default=2.5, + help="target size per video in GiB (default: 2.5)") + parser.add_argument("--dry-run", action="store_true", + help="print the planned encodes without running them") + args = parser.parse_args() + + folder = Path(args.folder) + if not folder.is_dir(): + sys.exit(f"error: folder does not exist: {folder}") + if not PRESET_FILE.is_file(): + sys.exit(f"error: preset file not found: {PRESET_FILE}") + + handbrake = find_tool("HandBrakeCLI", r"C:\Program Files\HandBrake\HandBrakeCLI.exe") + ffprobe = find_tool("ffprobe", r"C:\Program Files\ffmpeg\bin\ffprobe.exe") + target_bytes = int(args.target_gb * 1024**3) + + videos = sorted( + p for p in folder.iterdir() + if p.is_file() + and p.suffix.lower() in VIDEO_EXTS + and not p.stem.endswith(OUTPUT_SUFFIX) + ) + if not videos: + print(f"no videos found in {folder}") + return + + failures = 0 + for src in videos: + out = src.with_name(src.stem + OUTPUT_SUFFIX + ".mp4") + + if out.exists(): + print(f"SKIP {src.name} (output already exists)") + continue + if src.stat().st_size <= target_bytes: + print(f"SKIP {src.name} (already {fmt_gib(src.stat().st_size)}, at/below target)") + continue + + try: + duration = probe_duration(ffprobe, src) + except RuntimeError as e: + print(f"SKIP {src.name} ({e})") + failures += 1 + continue + + bitrate = calc_video_bitrate(duration, target_bytes) + cmd = [ + handbrake, + "--preset-import-file", str(PRESET_FILE), + "-Z", PRESET_NAME, + "-b", str(bitrate), + "-i", str(src), + "-o", str(out), + ] + + print(f"ENCODE {src.name}: {fmt_gib(src.stat().st_size)}, " + f"{duration / 3600:.2f} h, -b {bitrate} -> {out.name}") + if args.dry_run: + print(f" {' '.join(cmd)}") + continue + + result = subprocess.run(cmd) + if result.returncode != 0 or not out.exists(): + print(f"FAIL {src.name} (HandBrakeCLI exit {result.returncode})") + out.unlink(missing_ok=True) + failures += 1 + continue + + print(f"DONE {out.name}: {fmt_gib(out.stat().st_size)} " + f"(was {fmt_gib(src.stat().st_size)})") + + sys.exit(1 if failures else 0) + + +if __name__ == "__main__": + main() diff --git a/compress_hevc_v2.py b/compress_hevc_v2.py new file mode 100644 index 0000000..e726828 --- /dev/null +++ b/compress_hevc_v2.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 +"""Batch-compress every video in a folder to HEVC, v2. + +Same as compress_hevc.py but built for throughput on NVIDIA GPUs: +uses the "1080P HEVC NVENC v2" preset (hevc_nvenc_1080p_v2.json, must sit +next to this script), decodes on the GPU via NVDEC (--enable-hw-decoding), +and skips decomb entirely (preset has it off — progressive sources only!). + +Measured on a GTX 1060: ~400 fps vs ~240 fps for the v1 pipeline (1.65x), +which fully saturates the single NVENC engine — so running 2 jobs in +parallel (-j 2) is supported but gains nothing; one job is already +GPU-bound. + + python compress_hevc_v2.py # E:\\Media\\Compress-Temp + python compress_hevc_v2.py D:\\some\\folder # any other folder + python compress_hevc_v2.py -j 2 # 2 parallel encodes + python compress_hevc_v2.py --target-gb 3.0 # target size (default 2.5) + python compress_hevc_v2.py --dry-run # show plan, encode nothing + +WARNING: the v2 preset disables deinterlacing. Only feed it progressive +sources (check with: ffprobe -show_entries stream=field_order ...). + +Per-file video bitrate is derived from duration so every output lands near +the target size. Files at/below the target, *_hevc.mp4 outputs, and files +whose output already exists are skipped, so re-running resumes a batch. + +Progress: single-job runs show HandBrake's live progress on the console; +with -j 2 each job writes to .log in the same folder instead +(kept only on failure). +""" + +import argparse +import shutil +import subprocess +import sys +import threading +from concurrent.futures import ThreadPoolExecutor, as_completed +from pathlib import Path + +SCRIPT_DIR = Path(__file__).resolve().parent +PRESET_FILE = SCRIPT_DIR / "hevc_nvenc_1080p_v2.json" +PRESET_NAME = "1080P HEVC NVENC v2" + +DEFAULT_FOLDER = r"E:\Media\Compress-Temp" +VIDEO_EXTS = {".mp4", ".mkv", ".avi", ".mov", ".m4v", ".ts", ".wmv"} +OUTPUT_SUFFIX = "_hevc" + +AUDIO_KBPS = 160 # audio bitrate set by the preset +OVERSHOOT = 1.09 # NVENC delivers ~9% above the requested avg bitrate +MIN_VIDEO_KBPS = 800 # below this, 1080p HEVC falls apart visibly +MAX_VIDEO_KBPS = 8000 # no point going higher for re-compression +MAX_JOBS = 2 # consumer Pascal NVENC allows 2 concurrent sessions + +print_lock = threading.Lock() + + +def log(msg): + with print_lock: + print(msg, flush=True) + + +def find_tool(name, fallback): + path = shutil.which(name) + if path: + return path + if Path(fallback).exists(): + return fallback + sys.exit(f"error: '{name}' not found on PATH or at {fallback}") + + +def probe_duration(ffprobe, path): + out = subprocess.run( + [ffprobe, "-v", "error", "-show_entries", "format=duration", + "-of", "default=noprint_wrappers=1:nokey=1", str(path)], + capture_output=True, text=True, + ) + if out.returncode != 0: + raise RuntimeError(f"ffprobe failed for {path}: {out.stderr.strip()}") + return float(out.stdout.strip()) + + +def calc_video_bitrate(duration_s, target_bytes): + """Requested (-b) video kbps to land near target_bytes, given NVENC overshoot.""" + total_kbps = target_bytes * 8 / 1000 / duration_s + video_kbps = (total_kbps - AUDIO_KBPS) / OVERSHOOT + return int(round(max(MIN_VIDEO_KBPS, min(MAX_VIDEO_KBPS, video_kbps)))) + + +def fmt_gib(nbytes): + return f"{nbytes / 1024**3:.2f} GiB" + + +def run_encode(handbrake, src, out, bitrate, dry_run, show_progress): + cmd = [ + handbrake, + "--enable-hw-decoding", "nvdec", + "--preset-import-file", str(PRESET_FILE), + "-Z", PRESET_NAME, + "-b", str(bitrate), + "-i", str(src), + "-o", str(out), + ] + if dry_run: + log(f" {' '.join(cmd)}") + return True + + log_path = out.with_suffix(".log") + if show_progress: + # single job: let HandBrake draw its live progress on the console + result = subprocess.run(cmd) + else: + # parallel: keep consoles from garbling each other, log per job instead + log(f"START {src.name} (progress: {log_path})") + with open(log_path, "w") as log_file: + result = subprocess.run(cmd, stdout=log_file, + stderr=subprocess.STDOUT) + + if result.returncode != 0 or not out.exists(): + log(f"FAIL {src.name} (HandBrakeCLI exit {result.returncode})" + + ("" if show_progress else f", see {log_path}")) + out.unlink(missing_ok=True) + return False + + log_path.unlink(missing_ok=True) + log(f"DONE {out.name}: {fmt_gib(out.stat().st_size)} " + f"(was {fmt_gib(src.stat().st_size)})") + return True + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("folder", nargs="?", default=DEFAULT_FOLDER, + help=f"folder to scan (default: {DEFAULT_FOLDER})") + parser.add_argument("-j", "--jobs", type=int, default=1, choices=[1, 2], + help="parallel encodes (default: 1, max: 2 — NVENC session limit)") + parser.add_argument("--target-gb", type=float, default=2.5, + help="target size per video in GiB (default: 2.5)") + parser.add_argument("--dry-run", action="store_true", + help="print the planned encodes without running them") + args = parser.parse_args() + + folder = Path(args.folder) + if not folder.is_dir(): + sys.exit(f"error: folder does not exist: {folder}") + if not PRESET_FILE.is_file(): + sys.exit(f"error: preset file not found: {PRESET_FILE}") + + handbrake = find_tool("HandBrakeCLI", r"C:\Program Files\HandBrake\HandBrakeCLI.exe") + ffprobe = find_tool("ffprobe", r"C:\Program Files\ffmpeg\bin\ffprobe.exe") + target_bytes = int(args.target_gb * 1024**3) + + videos = sorted( + p for p in folder.iterdir() + if p.is_file() + and p.suffix.lower() in VIDEO_EXTS + and not p.stem.endswith(OUTPUT_SUFFIX) + ) + if not videos: + print(f"no videos found in {folder}") + return + + jobs = [] + failures = 0 + for src in videos: + out = src.with_name(src.stem + OUTPUT_SUFFIX + ".mp4") + + if out.exists(): + print(f"SKIP {src.name} (output already exists)") + continue + if src.stat().st_size <= target_bytes: + print(f"SKIP {src.name} (already {fmt_gib(src.stat().st_size)}, at/below target)") + continue + + try: + duration = probe_duration(ffprobe, src) + except RuntimeError as e: + print(f"SKIP {src.name} ({e})") + failures += 1 + continue + + bitrate = calc_video_bitrate(duration, target_bytes) + print(f"QUEUE {src.name}: {fmt_gib(src.stat().st_size)}, " + f"{duration / 3600:.2f} h, -b {bitrate} -> {out.name}") + jobs.append((src, out, bitrate)) + + with ThreadPoolExecutor(max_workers=args.jobs) as pool: + futures = [ + pool.submit(run_encode, handbrake, src, out, bitrate, + args.dry_run, args.jobs == 1) + for src, out, bitrate in jobs + ] + for future in as_completed(futures): + if not future.result(): + failures += 1 + + sys.exit(1 if failures else 0) + + +if __name__ == "__main__": + main() diff --git a/hevc_nvenc_1080p.json b/hevc_nvenc_1080p.json new file mode 100644 index 0000000..fdd8485 --- /dev/null +++ b/hevc_nvenc_1080p.json @@ -0,0 +1,112 @@ +{ + "PresetList": [ + { + "AlignAVStart": true, + "AudioCopyMask": [], + "AudioEncoderFallback": "av_aac", + "AudioLanguageList": [ + "any" + ], + "AudioList": [ + { + "AudioBitrate": 160, + "AudioCompressionLevel": 0, + "AudioEncoder": "av_aac", + "AudioMixdown": "stereo", + "AudioNormalizeMixLevel": false, + "AudioSamplerate": "auto", + "AudioTrackQualityEnable": false, + "AudioTrackQuality": -1, + "AudioTrackGainSlider": 0, + "AudioTrackDRCSlider": 0 + } + ], + "AudioSecondaryEncoderMode": true, + "AudioTrackSelectionBehavior": "all", + "ChapterMarkers": true, + "ChildrenArray": [], + "Default": true, + "FileFormat": "av_mp4", + "Folder": false, + "FolderOpen": false, + "Optimize": true, + "Mp4iPodCompatible": false, + "PictureCropMode": 0, + "PictureBottomCrop": 0, + "PictureLeftCrop": 0, + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureDARWidth": 1920, + "PictureDeblockPreset": "off", + "PictureDeblockTune": "medium", + "PictureDeblockCustom": "strength=strong:thresh=20:blocksize=8", + "PictureDeinterlaceFilter": "decomb", + "PictureCombDetectPreset": "default", + "PictureCombDetectCustom": "", + "PictureDeinterlacePreset": "default", + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureSharpenCustom": "", + "PictureSharpenFilter": "off", + "PictureSharpenPreset": "medium", + "PictureSharpenTune": "none", + "PictureDetelecine": "off", + "PictureDetelecineCustom": "", + "PictureColorspacePreset": "off", + "PictureColorspaceCustom": "", + "PictureChromaSmoothPreset": "off", + "PictureChromaSmoothCustom": "", + "PictureChromaSmoothTune": "none", + "PictureItuPAR": false, + "PictureKeepRatio": true, + "PicturePAR": "auto", + "PicturePARWidth": 1, + "PicturePARHeight": 1, + "PictureWidth": 1920, + "PictureHeight": 1080, + "PictureUseMaximumSize": true, + "PictureAllowUpscaling": false, + "PictureForceHeight": 0, + "PictureForceWidth": 0, + "PicturePadMode": "none", + "PicturePadTop": 0, + "PicturePadBottom": 0, + "PicturePadLeft": 0, + "PicturePadRight": 0, + "PresetName": "1080P HEVC NVENC", + "Type": 1, + "SubtitleAddCC": false, + "SubtitleAddForeignAudioSearch": false, + "SubtitleAddForeignAudioSubtitle": false, + "SubtitleBurnBehavior": "none", + "SubtitleBurnBDSub": false, + "SubtitleBurnDVDSub": false, + "SubtitleLanguageList": [ + "any" + ], + "SubtitleTrackSelectionBehavior": "none", + "VideoAvgBitrate": 1850, + "VideoColorMatrixCode": 0, + "VideoEncoder": "nvenc_h265", + "VideoFramerateMode": "vfr", + "VideoGrayScale": false, + "VideoScaler": "swscale", + "VideoPreset": "slow", + "VideoTune": "", + "VideoProfile": "main", + "VideoLevel": "auto", + "VideoOptionExtra": "", + "VideoQualityType": 1, + "VideoQualitySlider": 24, + "VideoMultiPass": true, + "VideoTurboMultiPass": true, + "x264UseAdvancedOptions": false, + "PresetDisabled": false, + "MetadataPassthrough": true + } + ], + "VersionMajor": 56, + "VersionMicro": 0, + "VersionMinor": 0 +} diff --git a/hevc_nvenc_1080p.md b/hevc_nvenc_1080p.md new file mode 100644 index 0000000..c7eef4b --- /dev/null +++ b/hevc_nvenc_1080p.md @@ -0,0 +1,73 @@ +# Preset: 1080P HEVC NVENC + +File: `hevc_nvenc_1080p.json` — HandBrake preset for GPU-accelerated HEVC (H.265) +compression of 1080p video using NVIDIA NVENC. + +## What it does + +- **Encoder**: `nvenc_h265` (HEVC on the GPU, not CPU x265) +- **Preset**: `slow` — best quality/speed balance on Pascal-class GPUs; + `slowest` gains almost nothing but nearly halves the speed +- **Rate control**: VBR, 1850 kbps video (multipass) + 160 kbps AAC stereo audio +- **Resolution**: unchanged up to 1920×1080 (larger sources are downscaled to fit, + aspect ratio preserved, no upscaling) +- **Framerate**: same as source (VFR passthrough) +- **Container**: MP4, web-optimized, chapters + metadata preserved +- **Subtitles**: not included + +Tuned so a ~3 hour 1080p source lands around **2.5–2.7 GiB**. Reference result: +8.06 GB h264 1080p source (2h59m) → 2.68 GiB HEVC, ~26 min encode on a GTX 1060 +(~220 fps average). + +## Requirements + +- HandBrake 1.8+ (`HandBrakeCLI.exe` for command line use) +- NVIDIA GPU with HEVC NVENC support (GTX 10-series or newer) and recent drivers + +## Usage — command line + +```bash +HandBrakeCLI --preset-import-file hevc_nvenc_1080p.json \ + -Z "1080P HEVC NVENC" \ + -i input.mp4 -o output.mp4 +``` + +Windows example: + +```powershell +& "C:\Program Files\HandBrake\HandBrakeCLI.exe" ` + --preset-import-file hevc_nvenc_1080p.json ` + -Z "1080P HEVC NVENC" ` + -i "F:\Media\input.mp4" -o "F:\Media\output.mp4" +``` + +## Usage — HandBrake GUI + +1. Open HandBrake → **Presets** panel → **Import** (bottom of the panel). +2. Select `hevc_nvenc_1080p.json`. +3. Open your source, choose the **1080P HEVC NVENC** preset, set the output path, Start. + +## Adjusting the target size + +The output size is driven by `VideoAvgBitrate` (kbps) and the video duration: + +``` +VideoAvgBitrate ≈ (target_bytes × 8 / 1000 − audio_kbps × duration_s) / duration_s +``` + +For a 2.5 GiB target with 160 kbps audio, that simplifies to roughly: + +``` +VideoAvgBitrate ≈ 21500000 / duration_seconds − 160 +``` + +| Duration | VideoAvgBitrate | Approx. output | +|----------|-----------------|----------------| +| 1 h | ~5800 kbps | ~2.5 GiB | +| 1.5 h | ~3800 kbps | ~2.5 GiB | +| 2 h | ~2800 kbps | ~2.5 GiB | +| 3 h | 1850 kbps (current) | ~2.6 GiB | +| 4 h | ~1330 kbps | ~2.5 GiB | + +Raise the value for better quality (larger file), lower it for a smaller file. +For 1080p HEVC, going below ~1200 kbps starts to show visible artifacts. diff --git a/hevc_nvenc_1080p_v2.json b/hevc_nvenc_1080p_v2.json new file mode 100644 index 0000000..6d8d51e --- /dev/null +++ b/hevc_nvenc_1080p_v2.json @@ -0,0 +1,112 @@ +{ + "PresetList": [ + { + "AlignAVStart": true, + "AudioCopyMask": [], + "AudioEncoderFallback": "av_aac", + "AudioLanguageList": [ + "any" + ], + "AudioList": [ + { + "AudioBitrate": 160, + "AudioCompressionLevel": 0, + "AudioEncoder": "av_aac", + "AudioMixdown": "stereo", + "AudioNormalizeMixLevel": false, + "AudioSamplerate": "auto", + "AudioTrackQualityEnable": false, + "AudioTrackQuality": -1, + "AudioTrackGainSlider": 0, + "AudioTrackDRCSlider": 0 + } + ], + "AudioSecondaryEncoderMode": true, + "AudioTrackSelectionBehavior": "all", + "ChapterMarkers": true, + "ChildrenArray": [], + "Default": true, + "FileFormat": "av_mp4", + "Folder": false, + "FolderOpen": false, + "Optimize": true, + "Mp4iPodCompatible": false, + "PictureCropMode": 0, + "PictureBottomCrop": 0, + "PictureLeftCrop": 0, + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureDARWidth": 1920, + "PictureDeblockPreset": "off", + "PictureDeblockTune": "medium", + "PictureDeblockCustom": "strength=strong:thresh=20:blocksize=8", + "PictureDeinterlaceFilter": "off", + "PictureCombDetectPreset": "off", + "PictureCombDetectCustom": "", + "PictureDeinterlacePreset": "off", + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureSharpenCustom": "", + "PictureSharpenFilter": "off", + "PictureSharpenPreset": "medium", + "PictureSharpenTune": "none", + "PictureDetelecine": "off", + "PictureDetelecineCustom": "", + "PictureColorspacePreset": "off", + "PictureColorspaceCustom": "", + "PictureChromaSmoothPreset": "off", + "PictureChromaSmoothCustom": "", + "PictureChromaSmoothTune": "none", + "PictureItuPAR": false, + "PictureKeepRatio": true, + "PicturePAR": "auto", + "PicturePARWidth": 1, + "PicturePARHeight": 1, + "PictureWidth": 1920, + "PictureHeight": 1080, + "PictureUseMaximumSize": true, + "PictureAllowUpscaling": false, + "PictureForceHeight": 0, + "PictureForceWidth": 0, + "PicturePadMode": "none", + "PicturePadTop": 0, + "PicturePadBottom": 0, + "PicturePadLeft": 0, + "PicturePadRight": 0, + "PresetName": "1080P HEVC NVENC v2", + "Type": 1, + "SubtitleAddCC": false, + "SubtitleAddForeignAudioSearch": false, + "SubtitleAddForeignAudioSubtitle": false, + "SubtitleBurnBehavior": "none", + "SubtitleBurnBDSub": false, + "SubtitleBurnDVDSub": false, + "SubtitleLanguageList": [ + "any" + ], + "SubtitleTrackSelectionBehavior": "none", + "VideoAvgBitrate": 1850, + "VideoColorMatrixCode": 0, + "VideoEncoder": "nvenc_h265", + "VideoFramerateMode": "vfr", + "VideoGrayScale": false, + "VideoScaler": "swscale", + "VideoPreset": "slow", + "VideoTune": "", + "VideoProfile": "main", + "VideoLevel": "auto", + "VideoOptionExtra": "", + "VideoQualityType": 1, + "VideoQualitySlider": 24, + "VideoMultiPass": true, + "VideoTurboMultiPass": true, + "x264UseAdvancedOptions": false, + "PresetDisabled": false, + "MetadataPassthrough": true + } + ], + "VersionMajor": 56, + "VersionMicro": 0, + "VersionMinor": 0 +}