强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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. 网络带宽:确保上行带宽足够,建议至少为目标码率的 1.5 倍
  2. 编码延迟:使用 -preset ultrafast -tune zerolatency 降低延迟
  3. 缓冲区设置-bufsize 通常设为 -maxrate 的 2 倍
  4. 分片时长:HLS/DASH 分片时长影响延迟和兼容性
  5. 协议选择:根据使用场景选择合适的协议

业务场景

场景 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"

扩展阅读

  1. HLS 规范
  2. DASH 规范
  3. RTMP 规范
  4. SRT 协议
  5. WebRTC 规范

总结

本章介绍了 FFmpeg 的流媒体功能,包括:

  • 流媒体协议概览
  • RTMP 推流
  • HLS 和 DASH 分片
  • RTSP 拉流
  • 流媒体转码和录制

掌握这些功能可以帮助您构建流媒体应用。