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 保证每段可独立解码。
核心实现
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")
运行与验证
- 准备输入:
ffmpeg -f lavfi -i testsrc=size=640x480:rate=25 -t 35 input.mp4生成 35 秒测试视频。 - 执行:
python encode.py。 - 通过条件:
segments/下出现seg_000.ts起连续编号文件,数量约为ceil(35/10)=4;每段可用ffplay seg_000.ts独立播放。 - 切换 H.265:把
codec="libx265"重跑,文件名与分段逻辑不变,仅编码器不同。
常见问题
- 分段边界不齐:确认
-force_key_frames表达式与-segment_time一致。 - 时间戳错乱:保留
-reset_timestamps 1,使每段从 0 开始。 - libx265 缺失:
ffmpeg -encoders | grep 265检查,缺失则改用 libx264。