diff --git a/public/banners/does-hevc-actually-shrink-your-files.png b/public/banners/does-hevc-actually-shrink-your-files.png new file mode 100644 index 0000000..451e2bc Binary files /dev/null and b/public/banners/does-hevc-actually-shrink-your-files.png differ diff --git a/public/og/does-hevc-actually-shrink-your-files.png b/public/og/does-hevc-actually-shrink-your-files.png new file mode 100644 index 0000000..d288657 Binary files /dev/null and b/public/og/does-hevc-actually-shrink-your-files.png differ diff --git a/scripts/banner-gen/generate.mjs b/scripts/banner-gen/generate.mjs index 614aff1..03395f4 100644 --- a/scripts/banner-gen/generate.mjs +++ b/scripts/banner-gen/generate.mjs @@ -1185,6 +1185,24 @@ BANNERS['it-reported-success-nothing-had-changed'] = { ], }; +BANNERS['does-hevc-actually-shrink-your-files'] = { + titlebar: "root@media - does HEVC shrink it?", + lines: [ + { t: 'prompt', text: "$" }, { t: 'cmd', text: "measure.sh --source h264-a.mp4" }, + { t: 'dim', text: "nvenc cq27 -> 72.4% of source bitrate" }, { t: 'err', text: "nvenc cq27 -> 115.2% on the 720p file" }, + { t: 'prompt', text: "$" }, { t: 'cmd', text: "libx265 -crf 26 -preset medium" }, + { t: 'ok', text: "33.7% / 56.7% / 67.0% at min SSIM 0.99" }, { t: 'hl', text: "same quality, or the comparison is noise" }, + { t: 'dim', text: "software beats hardware by 10-22%" }, { t: 'dim', text: "VP9/AV1 sources: no headroom, copy" }, + ], + flow: [ + { n: '1', label: "classify bpp" }, + { n: '2', label: "encode" }, + { n: '3', label: "ssim" }, + { n: '4', label: "compare" }, + { n: '5', label: "cap size" }, + ], +}; + // ---------- read frontmatter ---------- const postPath = join(ROOT, 'src', 'content', 'posts', `${slug}.md`); let category = 'devops'; diff --git a/scripts/og-gen/generate.mjs b/scripts/og-gen/generate.mjs index fd12051..078c097 100644 --- a/scripts/og-gen/generate.mjs +++ b/scripts/og-gen/generate.mjs @@ -361,6 +361,12 @@ TERMINALS['it-reported-success-nothing-had-changed'] = `
$read-back hash -> mismatch
 re-upload -> hash match-> verified
`; +TERMINALS['does-hevc-actually-shrink-your-files'] = ` +
$hevc_nvenc -cq 27 -> 115% of source bitrate
+
 the "high quality" default made it BIGGER
+
$libx265 -crf 26 -> 56.7%
+
 min SSIM 0.988 · 22% smaller than NVENC-> measured
`; + // ---------- read frontmatter ---------- const postPath = join(ROOT, 'src', 'content', 'posts', `${slug}.md`); if (!existsSync(postPath)) { diff --git a/src/content/posts/does-hevc-actually-shrink-your-files.md b/src/content/posts/does-hevc-actually-shrink-your-files.md new file mode 100644 index 0000000..82a8335 --- /dev/null +++ b/src/content/posts/does-hevc-actually-shrink-your-files.md @@ -0,0 +1,148 @@ +--- +title: "Does Re-encoding to HEVC Actually Shrink Your Files? I Measured It." +description: "A measured comparison of HEVC encoders on real files: NVENC at cq27 made two of three files bigger, software x265 landed 10–22% smaller at matched quality, and one 1080p source shrank 49% while another shrank 17%." +pubDate: 2026-10-08 +category: tutorials +tags: [ffmpeg, hevc, x265, nvenc, video] +ogImage: /og/does-hevc-actually-shrink-your-files.png +banner: /banners/does-hevc-actually-shrink-your-files.png +draft: false +--- + +## The assumption worth testing + +"Convert it to HEVC, the files get smaller." It is repeated often enough +that nobody measures it. I had a reason to: a library of 582 course videos +where re-encoding had made files **bigger** in 50 of 54 cases, with the +average output at 111% of the original. + +So I measured. Real files, one variable at a time, quality checked against +the source rather than assumed. + +The short version: + +- Re-encoding a **H.264** source to HEVC at matched quality shrank files by +**33–66%** — but the spread is huge and depends on the source, not just its +bitrate. +- A common "good quality" hardware setting (`hevc_nvenc` at cq27) made **two +of three** test files *larger* than the source. +- At matched quality, **software x265 is 10–22% smaller than NVENC**. Hardware +encoding buys time, not size. +- Re-encoding an already-efficient source (VP9/AV1 from YouTube) buys +nothing. It grows. + +## Method: measure at equal quality, or don't bother + +Comparing "output bitrate" alone is meaningless — any encoder can hit a low +bitrate by throwing quality away. The measurement has to hold quality fixed. + +I encode a 60-second window of each source at several settings, and for each +output: + +1. measure the output's **video bitrate** as a percentage of the source's +video bitrate (not the file size — audio is excluded so the two are +comparable), and 2. measure **SSIM against the source**, frame by frame, +downscaled to 480×270 for a stable metric, reporting min and mean. + +One prerequisite: the harness must be self-consistent. Comparing a file with +*itself* through the same code path must return SSIM 1.0000. When mine did not +— it returned 0.87 on a file compared with itself, because one side was +decoded from a mid-file seek on an open-GOP source — I could have "measured" +anything and believed it. + +```bash +# self-test: this must print 1.000000, or your comparison is lying to you +ffmpeg -i any.mp4 -f rawvideo -pix_fmt yuv420p a.yuv +ffmpeg -i any.mp4 -f rawvideo -pix_fmt yuv420p b.yuv +ffmpeg -i a.yuv -i b.yuv -lavfi ssim -f null - +``` + +## Results + +Three real sources from the library I was working on, all 25–30 fps H.264, +video bitrate as a percentage of the source's video bitrate: + +| Setting | 1080p music (2720 kbps, bpp 0.0437) | 720p (1208 kbps, bpp 0.0437) | 1080×1920 vertical (4490 kbps, bpp 0.0722) | +|---|---|---|---| +| `hevc_nvenc` cq27 | 72.4% (min SSIM 0.9963) | **115.2%** (0.9935) | **119.3%** (0.9930) | +| `hevc_nvenc` cq30 | 51.0% (0.9945) | 82.6% (0.9907) | 83.8% (0.9901) | +| `hevc_nvenc` cq31 | 43.0% (0.9941) | 72.9% (0.9894) | 74.3% (0.9890) | +| `hevc_nvenc` cq30 + AQ/lookahead | 55.8% (0.9958) | 88.1% (0.9914) | 84.4% (0.9935) | +| `libx265` crf26 | **33.7%** (0.9927) | **56.7%** (0.9879) | **67.0%** (0.9913) | +| `libx265` crf28 | 26.4% (0.9910) | 45.0% (0.9852) | 53.2% (0.9888) | + +Four things fall out of that table. + +**1. The famous default is the wrong default.** cq27 is where a lot of the +internet lands when it says "HEVC, high quality" — and on two of three files +it produced a *bigger* video stream than the source it was replacing. That +is not an argument that HEVC is worse than H.264. It is an argument that a +fixed quality knob calibrated on your own test clip means nothing on someone +else's encode. + +**2. The shrink depends on the source's efficiency, not its bitrate.** Samples +1 and 2 have identical bpp (bits per pixel per second) — 0.0437 — and one +shrank 49% where the other shrank 17%. The 720p file was already a decent +encode; the 1080p one was a fat one. Same bpp, different headroom. bpp is +still the cheapest first filter (it told me which *files* to re-encode), but +it does not predict the ratio. + +**3. Software x265 beats NVENC on size, at equal quality.** Compare the rows +at similar SSIM: cq31 vs crf26 (min SSIM 0.9894 vs 0.9927 on the 720p file) +— 72.9% vs 56.7%. That is a 22% smaller file at a *higher* measured quality. +Across the set, analysis gives roughly **10–22%** extra saving. NVENC is not +worse at encoding; it is optimized for throughput. If your constraint is +disk, spend CPU; if it is time, spend GPU. + +**4. Audio becomes the floor.** Sample 1's video stream dropped to 33.7% of +the source's video bitrate — but the *file* only reached 53.1% of the +original size on the full-length test, because after that drop the AAC audio +(matched to the source's audio bitrate, as iOS requires AAC in MP4) was +about 43% of the output's total bitrate. Once the video is this compressed, +the audio track is the next lever — and it is a much smaller one. + +## What this means for VP9/AV1 sources + +Everything above is about **H.264** sources. The modern YouTube formats are +a different story, and I measured that too: 14 sampled AVC1 sources had a +median bpp of 0.053 (the "compatibility ladder" YouTube serves to devices +that cannot do VP9/AV1 is generous), while the VP9/AV1 renditions of the +same material sit far lower. Re-encodable headroom: plenty on H.264, none on +VP9/AV1. + +On a library of YouTube-sourced VP9/AV1 files, re-encoding with a hardware +encoder at cq27 produced files at **105–112%** of the originals — measurably +worse than leaving them alone. The correct action there is `-c copy`: keep +the video stream bit-identical and re-encode only the audio container (MP3 +in MP4 is not playable on iOS; AAC is). + +## The decision rules I actually use now + +1. **Classify by bpp before encoding anything.** Bits per pixel per second +(`video_bitrate / (width × height × fps)`). It is one ffprobe call and it +separates "there is headroom here" from "leave it alone" better than +resolution or filesize does. 2. **Never re-encode a source that is already +efficient.** Copy the video stream, fix the audio if it needs it, and move +on. A re-encode cannot create headroom that is not there. 3. **Set quality, +not bitrate — then verify against the source.** A metric compared frame by +frame, with a self-test proving your harness works. 4. **Choose the encoder +by your bottleneck.** Disk → x265 (10–22% smaller at equal quality). Time → +NVENC. 5. **Cap the output.** Whatever you do, assert the result is not +bigger than the source. That single assertion would have caught the entire +111% problem before it touched 54 files. 6. **Remember the audio.** After +aggressive video compression, the audio track can be the largest remaining +component of the file. + +## The measured outcome + +On the 582-file library, with the tiering above and the read-back +verification I described elsewhere: + +- **copy tier** (efficient sources, video bit-identical): ~100% of the +original — by design, quality preserved exactly. +- **mid tier** (NVENC, cq31): landed around **72%**. +- **fat tier** (x265, crf26): landed **33–44%**, median **39%**. + +That is the honest answer to "does HEVC shrink my files": it depends on what +you are re-encoding, and the only way to know your number is to measure it +on your own files with quality held fixed. diff --git a/src/content/posts/zh/does-hevc-actually-shrink-your-files.md b/src/content/posts/zh/does-hevc-actually-shrink-your-files.md new file mode 100644 index 0000000..dfd4413 --- /dev/null +++ b/src/content/posts/zh/does-hevc-actually-shrink-your-files.md @@ -0,0 +1,89 @@ +--- +title: "转成 HEVC 到底会不会让文件变小?我实测了" +description: "在真实文件上对 HEVC 编码器做的实测对比:NVENC cq27 让三个测试文件中的两个变得更大;同画质下软件 x265 比 NVENC 小 10–22%;同样是 1080p,一个源缩了 49%,另一个只缩了 17%。" +pubDate: 2026-10-08 +category: tutorials +tags: [ffmpeg, hevc, x265, nvenc, video] +ogImage: /og/does-hevc-actually-shrink-your-files.png +banner: /banners/does-hevc-actually-shrink-your-files.png +draft: false +--- + +## 一个值得验证的假设 + +"转成 HEVC,文件就变小了。"这句话被重复得太多,以至于没人去实测它。我不得不测:我手上有一个 582 个课程视频的库,之前那轮重编码在 54 个文件里有 **50 个把文件变大了**,平均产出是原来的 111%。 + +所以我测了。真实文件、一次只改一个变量、画质对着源来量而不是靠假设。 + +简短版本: + +- **H.264** 源转 HEVC、同画质下能省 **33–66%**——但跨度极大,取决于源,而不只是取决于码率。 +- 一个很常见的"高质量"硬件设置(`hevc_nvenc` cq27)让**三个测试文件里的两个变得比源更大**。 +- 同画质下,**软件 x265 比 NVENC 小 10–22%**。硬件编码买的是时间,不是体积。 +- 对已经很高效率的源(YouTube 的 VP9/AV1)重编码一无所获,只会变大。 + +## 方法:要么在同画质下比,要么别比 + +只比"输出码率"是没有意义的——任何编码器都可以靠丢画质把码率压下来。测量必须把画质固定住。 + +我把每个源的 60 秒窗口用多种设置编码,然后对每一份输出: + +1. 量**输出的视频码率**占**源视频码率**的百分比(不是文件体积——把音频排除掉,两者才可比); +2. 量**输出对源的 SSIM**,逐帧、缩小到 480×270 以获得稳定的度量,报告最小值和均值。 + +有一个前提:这套度量工具必须自洽。把一个文件和**它自己**走同一条代码路径比对,必须得到 SSIM 1.0000。当我的工具做不到时——它在一个和自己的比对中给出了 0.87,因为其中一侧是从 open GOP 源的中间 seek 解码的——我本可以"测出"任何结论并信以为真。 + +```bash +# 自检:这里必须打印 1.000000,否则你的比对工具在骗你 +ffmpeg -i any.mp4 -f rawvideo -pix_fmt yuv420p a.yuv +ffmpeg -i any.mp4 -f rawvideo -pix_fmt yuv420p b.yuv +ffmpeg -i a.yuv -i b.yuv -lavfi ssim -f null - +``` + +## 结果 + +三个来自我在处理的素材库的真实源,都是 25–30 fps 的 H.264;表中数字为**输出视频码率占源视频码率的百分比**: + +| 设置 | 1080p 音乐(2720 kbps,bpp 0.0437) | 720p(1208 kbps,bpp 0.0437) | 1080×1920 竖屏(4490 kbps,bpp 0.0722) | +|---|---|---|---| +| `hevc_nvenc` cq27 | 72.4%(min SSIM 0.9963) | **115.2%**(0.9935) | **119.3%**(0.9930) | +| `hevc_nvenc` cq30 | 51.0%(0.9945) | 82.6%(0.9907) | 83.8%(0.9901) | +| `hevc_nvenc` cq31 | 43.0%(0.9941) | 72.9%(0.9894) | 74.3%(0.9890) | +| `hevc_nvenc` cq30 + AQ/lookahead | 55.8%(0.9958) | 88.1%(0.9914) | 84.4%(0.9935) | +| `libx265` crf26 | **33.7%**(0.9927) | **56.7%**(0.9879) | **67.0%**(0.9913) | +| `libx265` crf28 | 26.4%(0.9910) | 45.0%(0.9852) | 53.2%(0.9888) | + +这张表里掉出来四件事。 + +**1. 那个"著名默认值"是错的默认值。** 网上说"HEVC,高质量"时,很多人会落到 cq27 —— 而在三个文件里的两个上,它产出的视频流**比它要替换掉的源还大**。这并不是说 HEVC 比 H.264 差,而是说:一个在你自己的测试片段上校准出来的固定质量旋钮,对别人编好的文件毫无意义。 + +**2. 缩小的幅度取决于源的效率,而不是码率。** 样本 1 和样本 2 的 bpp(每像素每秒位数)完全相同——都是 0.0437——一个缩了 49%,另一个只缩了 17%。720p 那个本身已经是不错的编码,1080p 那个是"肥"的。同样的 bpp,不同的余量。bpp 仍是最便宜的第一道筛子(它告诉了我该重编码**哪些**文件),但它预测不了比例。 + +**3. 同画质下软件 x265 比 NVENC 更小。** 比较 SSIM 接近的那两行:cq31 vs crf26(在 720p 文件上 min SSIM 0.9894 vs 0.9927)——72.9% vs 56.7%,也就是说**文件小了 22%,而量出来的画质更高**。整体看,多出来的节省大约是 **10–22%**。这不是说 NVENC 编得差,而是它为吞吐量做了优化。约束是磁盘就花 CPU,约束是时间就花 GPU。 + +**4. 音频会成为地板。** 样本 1 的视频流降到了源视频码率的 33.7%——但在全片测试里,**整个文件**只降到原体积的 53.1%,因为在视频降下来之后,AAC 音轨(跟随源的音频码率,因为 iOS 要求 MP4 里是 AAC)大约占了输出总码率的 43%。视频压到这个程度之后,音轨就是下一个杠杆——而且是个小得多的杠杆。 + +## 这对 VP9/AV1 源意味着什么 + +上面讲的都是 **H.264** 源。现代 YouTube 格式是另一回事,我也测了:抽样 14 个 AVC1 源,bpp 中位数是 **0.053**(YouTube 给不支持 VP9/AV1 的设备发的那条"兼容梯队",码率给得很足),而同一批素材的 VP9/AV1 版本要低得多。可压缩的余量:H.264 上很多,VP9/AV1 上没有。 + +在一个由 YouTube VP9/AV1 组成的素材库上,用硬件编码器以 cq27 重编码,产出是原文件的 **105–112%**——明显不如不动它。这种情况下正确的动作是 `-c copy`:让视频流逐位不变,只重编音频容器(MP4 里的 MP3 在 iOS 上放不了,AAC 可以)。 + +## 我现在实际在用的判断规则 + +1. **动手之前先按 bpp 分类。** 每像素每秒位数(`视频码率 / (宽 × 高 × 帧率)`)。一次 ffprobe 调用,它区分"有余量"和"别碰它"的能力,比分辨率或文件大小都强。 +2. **已经很高效率的源绝不重编码。** 复制视频流、需要的话修音频,然后走开。重编码变不出本来不存在的余量。 +3. **设质量,不设码率——然后对着源验证。** 逐帧比对的度量,加上一个证明工具本身可用的自检。 +4. **按瓶颈选编码器。** 磁盘 → x265(同画质小 10–22%)。时间 → NVENC。 +5. **给输出加上限。** 无论怎么做,都要断言结果不比源更大。就这一条断言,本可以在那 54 个文件被碰之前就抓住整个 111% 的问题。 +6. **别忘了音频。** 视频被压狠之后,音轨可能是文件里剩下的最大部分。 + +## 实测结果 + +在那个 582 个文件的库上,用上面的分档和我另文写的回读校验: + +- **copy 档**(高效率源,视频逐位不变):约原体积的 **100%**——有意为之,画质精确保留。 +- **中间档**(NVENC,cq31):落在 **72%** 左右。 +- **"肥"档**(x265,crf26):落在 **33–44%**,中位数 **39%**。 + +这就是"HEVC 会不会让我的文件变小"的诚实答案:取决于你在重编码什么,而唯一知道你那个数字的办法,就是在你自己的文件上、把画质固定住去测一遍。