去年接手了一个在线教育平台的视频安全改造项目,客户要求对数千个课程视频进行加密分片处理。传统方案要么成本太高,要么性能堪忧,最终我们选择了FFmpeg+HLS的本地化处理方案。这套方案经过半年多的实战检验,单机日均处理量稳定在300+视频,特别适合中小型团队自主搭建视频处理流水线。
HLS(HTTP Live Streaming)作为当前主流的自适应流媒体协议,其核心是将视频切割成若干TS分片,通过M3U8索引文件实现动态加载。而加密环节则是通过AES-128标准对每个分片单独加密,密钥文件存放在独立服务器上。这种"分片+加密"的双重机制,既能防止视频被完整下载,又能适应不同网络环境下的流畅播放。
推荐使用Linux系统(Ubuntu 20.04 LTS实测最稳定),FFmpeg版本需≥4.3。安装命令如下:
bash复制sudo apt update
sudo apt install ffmpeg openssl -y
ffmpeg -version # 验证版本
注意:Windows系统下建议使用WSL2环境,纯CMD环境会遇到路径处理等兼容性问题
使用OpenSSL生成16字节密钥和IV(初始化向量):
bash复制openssl rand 16 > enc.key
openssl rand -hex 16 # 生成IV值
密钥文件建议存放在Nginx非web目录下(如/etc/nginx/keys/),通过单独的虚拟主机配置访问权限:
nginx复制location /keys {
internal; # 只允许内部请求
alias /etc/nginx/keys;
}
完整加密分片命令示例:
bash复制ffmpeg -i input.mp4 \
-c:v libx264 -crf 23 -preset fast \
-c:a aac -b:a 128k \
-hls_time 10 -hls_list_size 0 \
-hls_key_info_file enc.keyinfo \
-hls_segment_filename "v_%03d.ts" \
playlist.m3u8
关键参数说明:
-hls_time 10:每个分片10秒时长-crf 23:视频质量参数(18-28之间,值越小质量越高)enc.keyinfo文件内容格式:code复制http://yourdomain.com/keys/enc.key
/path/to/local/enc.key
Python自动化脚本示例:
python复制import os
import subprocess
video_dir = "./videos"
output_dir = "./output"
key_info = "enc.keyinfo"
for filename in os.listdir(video_dir):
if filename.endswith((".mp4", ".mov")):
input_path = os.path.join(video_dir, filename)
output_path = os.path.join(output_dir, filename.split('.')[0])
cmd = [
"ffmpeg", "-i", input_path,
"-c:v", "libx264", "-crf", "23",
"-c:a", "aac", "-b:a", "128k",
"-hls_time", "10", "-hls_list_size", "0",
"-hls_key_info_file", key_info,
"-hls_segment_filename", f"{output_path}_%03d.ts",
f"{output_path}.m3u8"
]
subprocess.run(cmd, check=True)
bash复制-c:v h264_nvenc # NVIDIA显卡
-c:v h264_qsv # Intel核显
bash复制-threads 4 -preset faster
bash复制-bufsize 1000k -maxrate 2000k
nginx复制# 确保Nginx配置了正确的CORS头
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET";
bash复制-hls_flags split_by_time # 强制按时间切割
bash复制-avoid_negative_ts make_zero -fflags +genpts
通过定时任务每天更新密钥:
bash复制0 3 * * * openssl rand 16 > /etc/nginx/keys/enc_$(date +\%Y\%m\%d).key
对应的M3U8文件需要动态更新URI:
code复制#EXT-X-KEY:METHOD=AES-URI="http://yourdomain.com/keys/enc_20230815.key"
Nginx配置示例:
nginx复制valid_referers server_names *.yourdomain.com;
if ($invalid_referer) {
return 403;
}
code复制/videos
/raw # 原始视频
/processing # 处理中
/encrypted # 成品
/logs
/ffmpeg # 处理日志
/keys
/rotation # 历史密钥备份
inotifywait监控处理目录bash复制grep "Conversion failed" ffmpeg.log | wc -l
python复制try:
subprocess.run(cmd, timeout=3600, check=True)
except subprocess.TimeoutExpired:
os.remove(output_path) # 清理残损文件
这套方案在我们实际项目中实现了:
最后分享一个实用技巧:在处理4K素材时,可以先用-ss 00:05:00 -t 10参数抽取片段测试,确认参数效果后再全量处理,能节省大量试错时间。