3. 车载视频编码与本地存储

车载视频编码与本地存储 学习卡片

任务目标

把采集到的原始视频帧编码为 H.264/H.265 码流,按时间分段写入本地文件,每段独立可播放。本案例用 FFmpeg 命令行完成编码与分段,用 Python 负责调用与校验,形成最小可复现闭环。

环境与依赖

  • FFmpeg(含 libx264 / libx265),命令行可执行 ffmpeg -version。
  • Python 3.8+,仅用标准库 subprocess、pathlib、time。
  • 输入:一段原始视频(如 input.mp4 或摄像头设备)。

分段策略

用 FFmpeg 的 segment 复用器按固定时长切片,文件名带时间戳,编码器可选 libx264 或 libx265。分段边界由 -segment_time 控制,关键帧对齐由 -force_key_frames 保证每段可独立解码。

原始视频流 H.264/H.265 编码 + 关键帧对齐 segment 复用器 按时间切片 seg_000.ts seg_001.ts ...

核心实现

import subprocess, time
from pathlib import Path

def encode_segments(src, out_dir, codec="libx264", seg_sec=10, crf=23):
    """将 src 编码并按 seg_sec 秒分段写入 out_dir。"""
    out = Path(out_dir)
    out.mkdir(parents=True, exist_ok=True)
    pattern = str(out / "seg_%03d.ts")
    cmd = [
        "ffmpeg", "-y", "-i", src,
        "-c:v", codec,
        "-crf", str(crf),
        "-force_key_frames", f"expr:gte(t,n_forced*{seg_sec})",
        "-f", "segment",
        "-segment_time", str(seg_sec),
        "-reset_timestamps", "1",
        pattern,
    ]
    t0 = time.time()
    r = subprocess.run(cmd, capture_output=True, text=True)
    if r.returncode != 0:
        raise RuntimeError(r.stderr[-800:])
    segs = sorted(out.glob("seg_*.ts"))
    return segs, time.time() - t0

if __name__ == "__main__":
    segs, cost = encode_segments("input.mp4", "segments",
                                 codec="libx264", seg_sec=10)
    for s in segs:
        print(s.name, s.stat().st_size, "bytes")
    print(f"共 {len(segs)} 段, 耗时 {cost:.1f}s")

运行与验证

  1. 准备输入:ffmpeg -f lavfi -i testsrc=size=640x480:rate=25 -t 35 input.mp4 生成 35 秒测试视频。
  2. 执行:python encode.py。
  3. 通过条件:segments/ 下出现 seg_000.ts 起连续编号文件,数量约为 ceil(35/10)=4;每段可用 ffplay seg_000.ts 独立播放。
  4. 切换 H.265:把 codec="libx265" 重跑,文件名与分段逻辑不变,仅编码器不同。

常见问题

  • 分段边界不齐:确认 -force_key_frames 表达式与 -segment_time 一致。
  • 时间戳错乱:保留 -reset_timestamps 1,使每段从 0 开始。
  • libx265 缺失:ffmpeg -encoders | grep 265 检查,缺失则改用 libx264。