H.265/HEVC (High Efficiency Video Coding) delivers the same visual quality as H.264 in files 40–50 % smaller. FFmpeg with the libx265 encoder is the most powerful way to leverage this codec from the command line.
H.264 vs H.265 vs AV1: quick comparison
| Codec | Year | Compression | Speed | Compatibility | Licensing |
|---|---|---|---|---|---|
| H.264 (libx264) | 2003 | Good | Very fast | Universal | Patented |
| H.265 (libx265) | 2013 | Very good | Medium | Wide | Patented |
| AV1 (libaom) | 2018 | Excellent | Slow | Growing | Free |
| VP9 | 2013 | Very good | Slow | Wide | Free |
H.265 is the sweet spot between universal compatibility and compression efficiency.
Basic MP4 → H.265 conversion
# Re-encode to H.265 with default quality
ffmpeg -i input.mp4 -c:v libx265 -c:a copy output_h265.mp4
# Specify CRF (Constant Rate Factor)
# 0 = lossless | 18 = near-lossless | 28 = default | 51 = worst
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a copy output.mp4
# Recommended for web (good quality, reduced size)
ffmpeg -i input.mp4 -c:v libx265 -crf 24 -preset medium -c:a aac -b:a 128k output.mp4
The CRF parameter: quality control
# Visual comparison of CRF values
ffmpeg -i input.mp4 -c:v libx265 -crf 18 crf18_near_lossless.mp4
ffmpeg -i input.mp4 -c:v libx265 -crf 23 crf23_high.mp4
ffmpeg -i input.mp4 -c:v libx265 -crf 28 crf28_default.mp4
ffmpeg -i input.mp4 -c:v libx265 -crf 35 crf35_compressed.mp4
ls -lh *.mp4 # Compare sizes
Practical CRF guide:
- 18–20: master files, no perceptible loss
- 21–26: high-quality online distribution (YouTube, Vimeo)
- 27–32: streaming, general download
- 33–40: mobile, very limited bandwidth
Presets: speed vs compression
# Available presets (fastest → slowest):
# ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
# ultrafast — minimal compression, maximum speed (testing only)
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset ultrafast output.mp4
# medium — recommended balance for production
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset medium output.mp4
# slow — better compression, ideal for final deliverables
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset slow output.mp4
# Rule: same CRF + slower preset = smaller file at equal quality
Hardware acceleration (GPU)
# NVIDIA NVENC (NVIDIA GPUs)
ffmpeg -i input.mp4 -c:v hevc_nvenc -cq 28 -preset p4 output_nvenc.mp4
# cq: Constant Quality (NVENC equivalent of CRF)
# preset: p1 (fast) → p7 (slow/best quality)
# Intel Quick Sync Video (QSV)
ffmpeg -i input.mp4 -c:v hevc_qsv -global_quality 28 output_qsv.mp4
# Apple VideoToolbox (M1/M2/M3 Mac)
ffmpeg -i input.mp4 -c:v hevc_videotoolbox -q:v 60 output_mac.mp4
# AMD AMF (AMD GPUs on Windows)
ffmpeg -i input.mp4 -c:v hevc_amf -quality quality output_amd.mp4
# Check available encoders on your system
ffmpeg -encoders 2>/dev/null | grep hevc
Two-pass encoding
Two-pass encoding improves quality consistency when targeting a specific bitrate:
# Pass 1 — analysis
ffmpeg -i input.mp4 -c:v libx265 -b:v 2M -x265-params pass=1 -an -f null /dev/null
# Pass 2 — encoding
ffmpeg -i input.mp4 -c:v libx265 -b:v 2M -x265-params pass=2 -c:a aac -b:a 128k output.mp4
Batch convert a directory (Bash)
#!/bin/bash
mkdir -p output_h265
for f in *.mp4; do
name="${f%.mp4}"
echo "-> Converting: $f"
ffmpeg -i "$f" \
-c:v libx265 \
-crf 26 \
-preset medium \
-c:a aac \
-b:a 128k \
-movflags +faststart \
"output_h265/${name}_h265.mp4" \
-y
done
echo "Conversion complete"
echo "Original sizes:"
du -sh *.mp4
echo "H.265 sizes:"
du -sh output_h265/*.mp4
Python with subprocess
import subprocess
from pathlib import Path
def compress_h265(input_path, output_path, crf=26, preset='medium'):
"""Compress video to H.265 using FFmpeg from Python."""
cmd = [
'ffmpeg',
'-i', str(input_path),
'-c:v', 'libx265',
'-crf', str(crf),
'-preset', preset,
'-c:a', 'aac',
'-b:a', '128k',
'-movflags', '+faststart',
str(output_path),
'-y',
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"ERROR: {result.stderr[-500:]}")
return False
return True
# Batch conversion
directory = Path('input_videos')
for video in sorted(directory.glob('*.mp4')):
output = video.parent / 'h265' / video.name
output.parent.mkdir(exist_ok=True)
ok = compress_h265(video, output, crf=26)
if ok:
orig = video.stat().st_size / 1024 / 1024
comp = output.stat().st_size / 1024 / 1024
savings = (1 - comp / orig) * 100
print(f"OK: {video.name} → {orig:.1f}MB → {comp:.1f}MB ({savings:.0f}% smaller)")
Useful additional options
# Limit max resolution (scale down if wider than 1080p)
ffmpeg -i input.mp4 \
-vf "scale='min(1920,iw)':'min(1080,ih)':force_original_aspect_ratio=decrease" \
-c:v libx265 -crf 26 output.mp4
# Trim first 60 seconds
ffmpeg -i input.mp4 -t 60 -c:v libx265 -crf 26 first60s.mp4
# -movflags +faststart for web streaming (moves MP4 metadata to front)
ffmpeg -i input.mp4 -c:v libx265 -crf 26 -movflags +faststart output.mp4
# Inspect output video info
ffprobe -v quiet -print_format json -show_streams output.mp4 | python3 -m json.tool
When to use H.265
- Archive / master: CRF 18–22, preset slow
- Online distribution: CRF 24–28, preset medium
- Mobile streaming: CRF 30–35, preset fast
- Quick conversion (testing): preset ultrafast
For maximum compatibility (legacy players, smart TVs), use H.264. For best compression with modern compatibility, H.265 is the optimal choice in 2024.
Related conversions
Common video conversions that pair well with this guide: