FFmpeg 多媒体处理教程 / 流媒体基础
流媒体基础
概述
流媒体(Streaming Media)是指将多媒体内容通过网络实时传输的技术。FFmpeg 支持多种流媒体协议,包括 RTMP、HLS、DASH、RTSP 等,可用于推流、拉流和实时转码。
流媒体协议概览
常见协议对比
| 协议 | 全称 | 传输方式 | 延迟 | 兼容性 | 适用场景 |
|---|---|---|---|---|---|
| RTMP | Real-Time Messaging Protocol | TCP | 低 | 好 | 直播推流 |
| HLS | HTTP Live Streaming | HTTP | 高 | 极好 | 点播/直播 |
| DASH | Dynamic Adaptive Streaming over HTTP | HTTP | 中 | 好 | 点播/直播 |
| RTSP | Real-Time Streaming Protocol | TCP/UDP | 低 | 中 | 监控/视频会议 |
| SRT | Secure Reliable Transport | UDP | 低 | 中 | 专业直播 |
| WebRTC | Web Real-Time Communication | UDP | 极低 | 好 | 视频通话 |
协议选择建议
| 场景 | 推荐协议 | 原因 |
|---|---|---|
| 直播推流 | RTMP | 广泛支持,低延迟 |
| 直播观看 | HLS | 兼容性最好 |
| 点播服务 | HLS/DASH | 自适应码率 |
| 视频监控 | RTSP | 低延迟,双向通信 |
| 视频会议 | WebRTC | 超低延迟 |
| 专业制作 | SRT | 可靠传输 |
RTMP 推流
RTMP 基础
RTMP(Real-Time Messaging Protocol)是 Adobe 开发的协议,广泛用于直播推流。
基本推流命令
# 基本推流
ffmpeg -re -i input.mp4 -c:v libx264 -c:a aac -f flv rtmp://server/live/stream_key
# 使用硬件加速推流
ffmpeg -re -i input.mp4 -c:v h264_nvenc -c:a aac -f flv rtmp://server/live/stream_key
# 低延迟推流
ffmpeg -re -i input.mp4 \
-c:v libx264 -preset ultrafast -tune zerolatency \
-b:v 2M -maxrate 2M -bufsize 4M \
-c:a aac -b:a 128k \
-f flv rtmp://server/live/stream_key
RTMP 参数详解
| 参数 | 说明 | 推荐值 |
|---|---|---|
-re | 按原始帧率读取 | 必需 |
-preset | 编码预设 | ultrafast/fast |
-tune | 调优参数 | zerolatency |
-b:v | 视频码率 | 2-6M |
-maxrate | 最大码率 | 与 b:v 相同 |
-bufsize | 缓冲区大小 | 2× maxrate |
主流平台推流
Bilibili 推流:
ffmpeg -re -i input.mp4 \
-c:v libx264 -preset fast -tune zerolatency \
-b:v 3M -maxrate 3M -bufsize 6M \
-c:a aac -b:a 128k \
-f flv rtmp://live-push.bilivideo.com/live-bvc/?streamname=your_stream_key
YouTube 推流:
ffmpeg -re -i input.mp4 \
-c:v libx264 -preset fast -tune zerolatency \
-b:v 4M -maxrate 4M -bufsize 8M \
-c:a aac -b:a 128k \
-f flv rtmp://a.rtmp.youtube.com/live2/your_stream_key
Twitch 推流:
ffmpeg -re -i input.mp4 \
-c:v libx264 -preset fast -tune zerolatency \
-b:v 3M -maxrate 3M -bufsize 6M \
-c:a aac -b:a 128k \
-f flv rtmp://live-jfk.twitch.tv/app/your_stream_key
推流脚本
#!/bin/bash
# rtmp_push.sh
INPUT=$1
SERVER=$2
KEY=$3
BITRATE=${4:-3M}
ffmpeg -re -i "$INPUT" \
-c:v libx264 -preset fast -tune zerolatency \
-b:v "$BITRATE" -maxrate "$BITRATE" -bufsize $((${BITRATE%M}*2))M \
-c:a aac -b:a 128k \
-f flv "${SERVER}/${KEY}"
HLS 流媒体
HLS 基础
HLS(HTTP Live Streaming)是 Apple 开发的协议,通过 HTTP 传输,兼容性极好。
基本 HLS 命令
# 基本 HLS 分片
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f hls -hls_time 4 -hls_list_size 0 \
-hls_segment_filename "segment_%03d.ts" \
playlist.m3u8
# 带多个码率的 HLS
ffmpeg -i input.mp4 \
-map 0:v -map 0:a -map 0:v -map 0:a -map 0:v -map 0:a \
-c:v libx264 -c:a aac \
-b:v:0 2M -b:v:1 1M -b:v:2 500k \
-f hls \
-hls_time 4 -hls_list_size 0 \
-var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
-master_pl_name master.m3u8 \
"stream_%v/playlist.m3u8"
HLS 参数详解
| 参数 | 说明 | 推荐值 |
|---|---|---|
-hls_time | 分片时长(秒) | 2-10 |
-hls_list_size | 播放列表大小 | 0(全部) |
-hls_segment_filename | 分片文件名 | segment_%03d.ts |
-hls_flags | HLS 选项 | delete_segments |
-hls_wrap | 分片序号回绕 | 不推荐使用 |
-hls_allow_cache | 允许缓存 | 1 |
HLS 选项
| 选项 | 说明 |
|---|---|
delete_segments | 删除旧分片 |
append_list | 追加到播放列表 |
round_durations | 圆整时长 |
discont_start | 不连续开始 |
omit_endlist | 省略 ENDLIST |
split_by_time | 按时间分割 |
independent_segments | 独立分片 |
自适应码率 HLS
#!/bin/bash
# hls_adaptive.sh
INPUT=$1
OUTPUT_DIR=${2:-hls}
mkdir -p "$OUTPUT_DIR"
# 多码率 HLS
ffmpeg -i "$INPUT" \
-map 0:v -map 0:a -map 0:v -map 0:a -map 0:v -map 0:a \
-c:v libx264 -c:a aac \
-b:v:0 5M -maxrate:v:0 5M -bufsize:v:0 10M \
-b:v:1 2M -maxrate:v:1 2M -bufsize:v:1 4M \
-b:v:2 800k -maxrate:v:2 800k -bufsize:v:2 1600k \
-s:v:0 1920x1080 -s:v:1 1280x720 -s:v:2 640x360 \
-f hls \
-hls_time 4 \
-hls_list_size 0 \
-hls_segment_filename "$OUTPUT_DIR/stream_%v/segment_%03d.ts" \
-var_stream_map "v:0,a:0,name:1080p v:1,a:1,name:720p v:2,a:2,name:360p" \
-master_pl_name "$OUTPUT_DIR/master.m3u8" \
"$OUTPUT_DIR/stream_%v/playlist.m3u8"
echo "HLS 生成完成: $OUTPUT_DIR/master.m3u8"
HLS 加密
# 生成密钥
openssl rand 16 > encryption.key
# 创建密钥信息文件
cat > encryption_key_info.txt << EOF
encryption.key
$(cat encryption.key | base64)
$(openssl rand -hex 16)
EOF
# 加密 HLS
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f hls -hls_time 4 -hls_list_size 0 \
-hls_key_info_file encryption_key_info.txt \
-hls_segment_filename "segment_%03d.ts" \
encrypted.m3u8
DASH 流媒体
DASH 基础
DASH(Dynamic Adaptive Streaming over HTTP)是开放标准,支持自适应码率。
基本 DASH 命令
# 基本 DASH 分片
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f dash \
-seg_duration 4 \
-window_size 5 \
-extra_window_size 10 \
manifest.mpd
# 多码率 DASH
ffmpeg -i input.mp4 \
-map 0:v -map 0:a -map 0:v -map 0:a \
-c:v libx264 -c:a aac \
-b:v:0 2M -b:v:1 1M \
-f dash \
-seg_duration 4 \
-adaptation_sets "id=0,streams=v id=1,streams=a" \
manifest.mpd
DASH 参数详解
| 参数 | 说明 | 推荐值 |
|---|---|---|
-seg_duration | 分片时长(秒) | 2-10 |
-window_size | 滑动窗口大小 | 5 |
-extra_window_size | 额外窗口大小 | 10 |
-remove_at_exit | 退出时删除 | 1 |
-use_template | 使用模板 | 1 |
-use_timeline | 使用时间线 | 1 |
-adaptation_sets | 自适应集 | 根据流配置 |
自适应码率 DASH
#!/bin/bash
# dash_adaptive.sh
INPUT=$1
OUTPUT_DIR=${2:-dash}
mkdir -p "$OUTPUT_DIR"
ffmpeg -i "$INPUT" \
-map 0:v -map 0:a -map 0:v -map 0:a -map 0:v -map 0:a \
-c:v libx264 -c:a aac \
-b:v:0 5M -maxrate:v:0 5M -bufsize:v:0 10M \
-b:v:1 2M -maxrate:v:1 2M -bufsize:v:1 4M \
-b:v:2 800k -maxrate:v:2 800k -bufsize:v:2 1600k \
-s:v:0 1920x1080 -s:v:1 1280x720 -s:v:2 640x360 \
-f dash \
-seg_duration 4 \
-adaptation_sets "id=0,streams=v id=1,streams=a" \
-window_size 5 \
-remove_at_exit 1 \
"$OUTPUT_DIR/manifest.mpd"
echo "DASH 生成完成: $OUTPUT_DIR/manifest.mpd"
RTSP 拉流
RTSP 基础
RTSP(Real-Time Streaming Protocol)常用于视频监控和实时通信。
基本拉流命令
# RTSP 拉流并保存
ffmpeg -i rtsp://camera_ip:554/stream -c copy output.mp4
# RTSP 拉流并转码
ffmpeg -i rtsp://camera_ip:554/stream \
-c:v libx264 -preset fast -c:a aac \
output.mp4
# RTSP 拉流并推流
ffmpeg -i rtsp://camera_ip:554/stream \
-c:v libx264 -preset fast -tune zerolatency \
-c:a aac \
-f flv rtmp://server/live/stream
RTSP 选项
# 设置 RTSP 传输方式
ffmpeg -rtsp_transport tcp -i rtsp://camera_ip:554/stream output.mp4
# 设置超时
ffmpeg -timeout 5000000 -i rtsp://camera_ip:554/stream output.mp4
# 设置缓冲区
ffmpeg -buffer_size 1024000 -i rtsp://camera_ip:554/stream output.mp4
流媒体转码
实时转码推流
# 基本实时转码
ffmpeg -i rtmp://source/live/stream \
-c:v libx264 -preset fast -tune zerolatency \
-b:v 2M -maxrate 2M -bufsize 4M \
-c:a aac -b:a 128k \
-f flv rtmp://target/live/stream
# 多码率转码
ffmpeg -i rtmp://source/live/stream \
-map 0:v -map 0:a -map 0:v -map 0:a \
-c:v libx264 -preset fast -tune zerolatency \
-c:a aac \
-b:v:0 4M -s:v:0 1920x1080 \
-b:v:1 2M -s:v:1 1280x720 \
-f tee \
"[f=flv]rtmp://target/live/stream_1080p|[f=flv]rtmp://target/live/stream_720p"
转码脚本
#!/bin/bash
# transcode_stream.sh
SOURCE=$1
TARGET=$2
BITRATE=${3:-2M}
ffmpeg -i "$SOURCE" \
-c:v libx264 -preset fast -tune zerolatency \
-b:v "$BITRATE" -maxrate "$BITRATE" -bufsize $((${BITRATE%M}*2))M \
-c:a aac -b:a 128k \
-f flv "$TARGET"
流媒体录制
直播录制
# 录制直播流
ffmpeg -i rtmp://server/live/stream -c copy output.mp4
# 录制并转码
ffmpeg -i rtmp://server/live/stream \
-c:v libx264 -crf 23 -c:a aac \
output.mp4
# 分段录制
ffmpeg -i rtmp://server/live/stream \
-c copy \
-f segment \
-segment_time 3600 \
-segment_format mp4 \
-strftime 1 \
"recording_%Y%m%d_%H%M%S.mp4"
HLS 录制
# 录制 HLS 流
ffmpeg -i https://example.com/live/playlist.m3u8 -c copy output.mp4
# 录制 HLS 分片
ffmpeg -i https://example.com/live/playlist.m3u8 \
-c copy \
-f segment \
-segment_time 60 \
"segment_%03d.ts"
流媒体服务器
使用 FFmpeg 搭建简单服务器
# 接收 RTMP 推流并转为 HLS
ffmpeg -listen 1 -i rtmp://0.0.0.0:1935/live/stream \
-c:v libx264 -c:a aac \
-f hls -hls_time 4 -hls_list_size 10 \
/var/www/html/live/stream.m3u8
# 接收 RTSP 流并转为 RTMP
ffmpeg -rtsp_transport tcp -i rtsp://camera_ip:554/stream \
-c:v libx264 -preset fast -tune zerolatency \
-c:a aac \
-f flv rtmp://localhost/live/camera
使用 tee 多路输出
# 同时输出到多个目标
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f tee \
"[f=flv]rtmp://server1/live/stream1|[f=mp4]output.mp4"
流媒体监控
流信息检测
# 检测 RTMP 流信息
ffprobe -v quiet -print_format json -show_streams rtmp://server/live/stream
# 检测 HLS 流信息
ffprobe -v quiet -print_format json -show_streams https://example.com/live/playlist.m3u8
# 检测 RTSP 流信息
ffprobe -v quiet -print_format json -show_streams rtsp://camera_ip:554/stream
流健康检查脚本
#!/bin/bash
# stream_health_check.sh
STREAM_URL=$1
# 获取流信息
INFO=$(ffprobe -v quiet -print_format json -show_streams "$STREAM_URL" 2>/dev/null)
if [ $? -ne 0 ]; then
echo "ERROR: 无法连接流"
exit 1
fi
# 检查视频流
VIDEO_CODEC=$(echo "$INFO" | jq -r '.streams[] | select(.codec_type=="video") | .codec_name')
VIDEO_WIDTH=$(echo "$INFO" | jq -r '.streams[] | select(.codec_type=="video") | .width')
VIDEO_HEIGHT=$(echo "$INFO" | jq -r '.streams[] | select(.codec_type=="video") | .height')
VIDEO_FPS=$(echo "$INFO" | jq -r '.streams[] | select(.codec_type=="video") | .r_frame_rate')
# 检查音频流
AUDIO_CODEC=$(echo "$INFO" | jq -r '.streams[] | select(.codec_type=="audio") | .codec_name')
AUDIO_SAMPLE_RATE=$(echo "$INFO" | jq -r '.streams[] | select(.codec_type=="audio") | .sample_rate')
echo "=== 流健康状态 ==="
echo "视频: $VIDEO_CODEC ${VIDEO_WIDTH}x${VIDEO_HEIGHT} @ ${VIDEO_FPS}fps"
echo "音频: $AUDIO_CODEC ${AUDIO_SAMPLE_RATE}Hz"
echo "状态: OK"
流媒体最佳实践
推流配置建议
| 场景 | 分辨率 | 帧率 | 视频码率 | 音频码率 |
|---|---|---|---|---|
| 游戏直播 | 1080p | 60fps | 6M | 192k |
| 聊天直播 | 720p | 30fps | 2M | 128k |
| 户外直播 | 720p | 30fps | 3M | 128k |
| 语音直播 | 480p | 30fps | 1M | 128k |
HLS 配置建议
| 参数 | 推荐值 | 说明 |
|---|---|---|
| hls_time | 2-6 秒 | 越短延迟越低 |
| hls_list_size | 0 或 10 | 0 表示全部 |
| 分片格式 | TS | 兼容性最好 |
| 编码 | H.264 + AAC | 广泛支持 |
DASH 配置建议
| 参数 | 推荐值 | 说明 |
|---|---|---|
| seg_duration | 2-6 秒 | 越短延迟越低 |
| window_size | 5 | 滑动窗口 |
| 编码 | H.264 + AAC | 广泛支持 |
注意事项
- 网络带宽:确保上行带宽足够,建议至少为目标码率的 1.5 倍
- 编码延迟:使用
-preset ultrafast -tune zerolatency降低延迟 - 缓冲区设置:
-bufsize通常设为-maxrate的 2 倍 - 分片时长:HLS/DASH 分片时长影响延迟和兼容性
- 协议选择:根据使用场景选择合适的协议
业务场景
场景 1:多平台同时推流
#!/bin/bash
# multi_platform_push.sh
INPUT=$1
# 使用 tee 同时推流到多个平台
ffmpeg -re -i "$INPUT" \
-c:v libx264 -preset fast -tune zerolatency \
-b:v 3M -maxrate 3M -bufsize 6M \
-c:a aac -b:a 128k \
-f tee \
"[f=flv]rtmp://live.bilibili.com/stream1|[f=flv]rtmp://live.twitch.tv/app/key2|[f=flv]rtmp://a.rtmp.youtube.com/live2/key3"
场景 2:监控摄像头转直播
#!/bin/bash
# camera_to_live.sh
CAMERA_RTSP=$1
RTMP_SERVER=$2
while true; do
ffmpeg -rtsp_transport tcp -i "$CAMERA_RTSP" \
-c:v libx264 -preset fast -tune zerolatency \
-b:v 2M -maxrate 2M -bufsize 4M \
-c:a aac -b:a 128k \
-f flv "$RTMP_SERVER"
echo "流断开,5 秒后重连..."
sleep 5
done
场景 3:直播录制回放
#!/bin/bash
# live_record_replay.sh
RTMP_URL=$1
OUTPUT_DIR=${2:-recordings}
mkdir -p "$OUTPUT_DIR"
# 录制
ffmpeg -i "$RTMP_URL" \
-c copy \
-f segment \
-segment_time 3600 \
-segment_format mp4 \
-strftime 1 \
"$OUTPUT_DIR/live_%Y%m%d_%H%M%S.mp4"
扩展阅读
总结
本章介绍了 FFmpeg 的流媒体功能,包括:
- 流媒体协议概览
- RTMP 推流
- HLS 和 DASH 分片
- RTSP 拉流
- 流媒体转码和录制
掌握这些功能可以帮助您构建流媒体应用。