3. H.264 与 H.265 关键帧提取与对比

H.264 与 H.265 关键帧提取与对比 学习卡片

任务说明

本案例对同一段原始视频分别用 H.264 和 H.265 编码,然后从两路码流中提取所有 I 帧(关键帧)保存为 PNG 图片,最后对比两种编码下关键帧的数量、时间分布和图像质量。核心工具是 FFmpeg,通过 -skip_frame nokey 只解码关键帧,再用 select 滤镜导出图片。

环境与依赖

  • FFmpeg(含 libx264、libx265 编码器),命令行执行 ffmpeg -version 确认。
  • 一段原始视频 input.mp4(建议 5~10 秒、含明显运动,便于观察关键帧分布)。
  • Python 3(仅用于统计关键帧数量与计算 PSNR,非必需但便于对比)。

处理流程

input.mp4 原始视频 libx264 编码 out_h264.mp4 libx265 编码 out_h265.mp4 skip_frame nokey 仅解码 I 帧 I 帧 PNG 对比分布/质量

完整实现

以下脚本完成:编码两路码流 → 提取 I 帧 → 统计数量与时间戳 → 计算两路 I 帧的 PSNR。将 input.mp4 放在脚本同目录后运行。

#!/usr/bin/env bash
# extract_keyframes.sh —— H.264 / H.265 关键帧提取与对比
set -e
IN="input.mp4"
[ -f "$IN" ] || { echo "缺少 $IN"; exit 1; }

# 1. 分别用 H.264 和 H.265 编码,固定 GOP=48 便于观察关键帧分布
ffmpeg -y -i "$IN" -c:v libx264 -g 48 -keyint_min 48 -sc_threshold 0 \
       -pix_fmt yuv420p -an out_h264.mp4
ffmpeg -y -i "$IN" -c:v libx265 -g 48 -keyint_min 48 -sc_threshold 0 \
       -pix_fmt yuv420p -an out_h265.mp4

# 2. 提取所有 I 帧为 PNG,文件名带帧序号
mkdir -p kf_h264 kf_h265
ffmpeg -y -skip_frame nokey -i out_h264.mp4 -vsync 0 \
       -frame_pts 1 kf_h264/i_%04d.png
ffmpeg -y -skip_frame nokey -i out_h265.mp4 -vsync 0 \
       -frame_pts 1 kf_h265/i_%04d.png

# 3. 统计关键帧数量
echo "H.264 I 帧数量: $(ls kf_h264/*.png | wc -l)"
echo "H.265 I 帧数量: $(ls kf_h265/*.png | wc -l)"

# 4. 打印每路码流的关键帧时间戳(pts_time)
echo "--- H.264 关键帧时间戳 ---"
ffprobe -v error -select_streams v:0 -skip_frame nokey \
        -show_entries frame=pts_time -of csv=p=0 out_h264.mp4
echo "--- H.265 关键帧时间戳 ---"
ffprobe -v error -select_streams v:0 -skip_frame nokey \
        -show_entries frame=pts_time -of csv=p=0 out_h265.mp4

质量对比用 PSNR 衡量两路码流相对原始视频的差异(数值越高越接近原始):

ffmpeg -i out_h264.mp4 -i "$IN" -lavfi psnr -f null - 2>&1 | grep "PSNR"
ffmpeg -i out_h265.mp4 -i "$IN" -lavfi psnr -f null - 2>&1 | grep "PSNR"

运行与验证

  1. 执行 bash extract_keyframes.sh,确认无报错并生成 kf_h264/、kf_h265/ 两个目录。
  2. 终端会打印两路 I 帧数量与时间戳列表。因两路都设了 -g 48 且关闭场景切换,关键帧数量应相同,时间戳也应基本一致——这验证了 GOP 结构对关键帧分布的决定作用。
  3. 打开两个目录中的 PNG,对比同一时间点 I 帧的清晰度与块效应。H.265 在相同码率下通常细节保留更好。
  4. 查看 PSNR 输出:average 值越大质量越高。若 H.265 的 PSNR 高于 H.264,说明同等条件下 H.265 压缩效率更优。

常见问题

  • 若 libx265 未安装,编码会失败,需安装带 libx265 的 FFmpeg 构建。
  • -skip_frame nokey 必须放在 -i 之前才生效。
  • 若关键帧数量与预期不符,检查是否被 -sc_threshold 0 关闭了场景切换插入 I 帧。