使用 FFmpeg 进行 VP9 直播编码
编码参数
VP9 提供了一系列参数来优化直播编码。比特率模式中讨论了这些原则的一些基本方面。
FFmpeg VP9 编码示例
下表介绍了 VP9 编码的示例 ffmpeg
调用的参数。
参数 | 说明 |
---|---|
-quality realtime |
realtime 对于直播和高于 5 的速度至关重要。 |
-speed 6 |
速度 5 到 8 应用于直播 / 实时编码。数字越小(5 或 6 ),质量越高,但需要更多 CPU 功率。数字越大(7 或 8 ),质量越低,但更适合低延迟用例,也更适合 CPU 功率较低的设备(例如移动设备)。 |
-tile-columns 4 |
平铺将视频拆分为矩形区域,从而实现多线程编码和解码。图块数量始终为 2 的幂。0 = 1 个分块,1 = 2,2 = 4,3 = 8,4 = 16,5 = 32。 |
-frame-parallel 1 |
启用并行解码功能。 |
-threads 8 |
要使用的线程数上限。 |
-static-thresh 0 |
运动检测阈值。 |
-max-intra-rate 300 |
I 帧比特率上限(百分比) |
-deadline realtime |
-quality realtime 的替代版本(旧版) |
-lag-in-frames 0 |
滞后帧数上限 |
-qmin 4 -qmax 48 |
量化器的最小值和最大值。此处的值仅为建议值,调整此值有助于提高/降低视频质量,但会牺牲压缩效率。 |
-row-mt 1 |
启用行多线程。允许使用最多 2 倍的线程作为平铺列。0 = 关闭,1 = 开启。 |
-error-resilient 1 |
启用错误恢复功能。 |
选择编码参数
以下信息使用恒定比特率 (CBR) 编码来实现自适应比特率 (ABR) 直播,其中每个目标速率都在封装程序的清单中明确设置。这样一来,客户端在不同费率之间的“切换”会更顺畅。如果比特率可以更灵活,或者编码正在分块,则可变比特率 (VBR) 编码和 CQ 模式也是不错的选择。Q 模式无法满足直播视频所需的实时编码。如需了解详情,请参阅比特率模式。
如需详细了解如何处理 VP9,还可参阅有关 VOD 设置的相关文章,但请注意重点是 CBR。
提示和技巧
请注意,在直播时,所有内容都受限于最低 1 倍的实时编码速度(FFmpeg 会在编码过程中报告编码速度)。如果编码速度降至低于 1 倍,编码过程将无法跟上直播视频的输入速度,用户会遇到缓冲问题,并且传输中断会导致直播期间无法使用直播流(不过归档内容通常可以使用)。
编码参数的实际应用示例
以下内容显示了在运行 Linux 的四核 i5 3.6Ghz 桌面设备上,各种帧大小在 25 fps 下的 CPU 利用率:
目标分辨率 | FFmpeg VP9 参数 | CPU / 速度(示例) |
---|---|---|
3840x2160 (2160p) | -r 30 -g 90 -s 3840x2160 -quality realtime -speed 5 -threads 16 -row-mt 1 -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 7800k | 约 88% 0.39 倍 |
2560x1440 (1440p) | -r 30 -g 90 -s 2560x1440 -quality realtime -speed 5 -threads 16 -row-mt 1 -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 6000k | 约 86% 0.68 倍 |
1920x1080 (1080p) | -r 30 -g 90 -s 1920x1080 -quality realtime -speed 5 -threads 8 -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 4500k | ~82% 1.04 倍 |
1280x720 (720p) | -r 30 -g 90 -s 1280x720 -quality realtime -speed 5 -threads 8 -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 3000k | ~78% 1.77 倍 |
854x480 (480p) | -r 30 -g 90 -s 854x480 -quality realtime -speed 6 -threads 4 -row-mt 1 -tile-columns 1 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 1800k | 约 64% 3.51 倍 |
640x360 (360p) | -r 30 -g 90 -s 640x360 -quality realtime -speed 7 -threads 4 -row-mt 1 -tile-columns 1 -frame-parallel 0 -qmin 4 -qmax 48 -b:v 730k | ~62% 5.27x |
426x240 (240p) | -r 30 -g 90 -s 426x240 -quality realtime -speed 8 -threads 2 -row-mt 1 -tile-columns 0 -frame-parallel 0 -qmin 4 -qmax 48 -b:v 365k | ~66% 8.27 倍 |
一个 FFmpeg 示例可能如下所示:
ffmpeg -stream_loop 100 -i /home/id3as/Videos/120s_tears_of_steel_1080p.webm \
-r 30 -g 90 -s 3840x2160 -quality realtime -speed 5 -threads 16 -row-mt 1 \
-tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 7800k -c:v libvpx-vp9 \
-b:a 128k -c:a libopus -f webm pipe1
提示和技巧
请注意,这里我们将输出内容发送到 FIFO 管道(“pipe1”),该管道应在执行 FFmpeg 命令之前创建。为此,请在工作目录中运行命令
mkfifo pipe1
。使用 Shaka Packager 时,它将监听该管道,将其作为指定视频流的输入源。其他包装型号可能需要采用不同的方法。为确保系统能够识别
-row-mt
命令,请从 https://www.ffmpeg.org/download.html 下载最新稳定版 FFmpeg(目前为 3.3.3)。
自适应比特率设置示例
根据运行 FFmpeg 编码的机器的性能,可能可以同时提供以下所有编码,也可能无法同时提供。因此,您应从列表中选择适合您自己的可用资源和目标受众群体的子集。
FFmpeg 完整 ABR 集
在理想情况下,我们会结合上一部分中概述的编码示例,创建一个可同时生成所有这些编码的命令:
ffmpeg -stream_loop 100 -i lakes1080p.mp4 \
-y -r 25 -g 75 -s 3840x2160 -quality realtime -speed 5 -threads 8 \
-tile-columns 2 -frame-parallel 1 \
-b:v 7800k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe1 \
-y -r 25 -g 75 -s 2560x1440 -quality realtime -speed 5 -threads 8 \
-tile-columns 2 -frame-parallel 1 \
-b:v 6000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe2 \
-y -r 25 -g 75 -s 1920x1080 -quality realtime -speed 5 -threads 4 \
-tile-columns 2 -frame-parallel 1 \
-b:v 4500k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe3 \
-y -r 25 -g 75 -s 1280x720 -quality realtime -speed 5 -threads 4 \
-tile-columns 2 -frame-parallel 1 \
-b:v 3000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe4 \
-y -r 25 -g 75 -s 854x480 -quality realtime -speed 6 -threads 4 \
-tile-columns 2 -frame-parallel 1 \
-b:v 2000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe5 \
-y -r 25 -g 75 -s 640x360 -quality realtime -speed 7 -threads 2 \
-tile-columns 1 -frame-parallel 0 \
-b:v 730k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe6 \
-y -r 25 -g 75 -s 426x240 -quality realtime -speed 8 -threads 2 \
-tile-columns 1 -frame-parallel 0 \
-b:v 365k -c:v libvpx-vp9 -b:a 64k -c:a libopus -f webm pipe7
不过,上述完整集需要非常强大的 CPU,或者可能需要硬件 GPU 分流的支持,例如某些芯片组越来越能提供这种支持。Intel Kabylake(及更高版本)具有完整的硬件编码流水线。(请注意,Kabylake GPU 可以进行 8 位 VP9 编码,但不能进行 10 位 VP9 编码)。
使用 Shaka Packager 的实用桌面示例
对于常见的桌面机器,一个更实用的示例可能会使用 Shaka Packager。设置 Shaka 的一种简单方法是使用 Google 的 DockerHub 映像将其安装在 Docker 容器中。如需查看相关说明,请点击以下链接:
https://github.com/google/shaka-packager#using-docker-for-testing--development
在此示例中,我们使用的机器具有以下配置:
系统 | 主机:obs 内核:4.4.0-91-lowlatency x86_64(64 位) |
桌面设备 | Xfce 4.12.3 发行版:操作系统:https://ubuntustudio.org/2016/10/ubuntu-studio-16-10-released/ |
CPU | 四核 Intel Core i5-6500 (-MCP-) 缓存:6144 KB 时钟速度:最高:3600 MHz 1:800 MHz 2:800 MHz 3:800 MHz 4:800 MHz |
显卡 | Intel Skylake 集成显卡 |
内存 | 8GB RAM |
在实践中,此机器可以最佳地生成以下可用的 ABR 编码范围,并且 FFmpeg 始终报告 1 倍的编码速度:
ffmpeg -stream_loop 100 -i 120s_tears_of_steel_1080p.webm \
-y -r 30 -g 90 -s 1920x1080 -quality realtime -speed 7 -threads 8 \
-row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 \
-b:v 4500k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe1 \
-y -r 30 -g 90 -s 1280x720 -quality realtime -speed 8 -threads 6 \
-row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 \
-b:v 3000k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe2 \
-y -r 30 -g 90 -s 640x360 -quality realtime -speed 8 -threads 2 \
-row-mt 1 -tile-columns 1 -frame-parallel 1 -qmin 4 -qmax 48 \
-b:v 730k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe3
请注意,-speed
设置非常高。这些设置是通过实验确定的,会因机器而异。
Shaka Packager 开销
打包并不是一项特别占用 CPU 的活动。即使 FFmpeg 只传送部分输出,也可以将 Shaka Packager 设置为监听所有输出。以下是在上述机器上测试的打包程序设置:
packager \
in=pipe1,stream=audio,init_segment=livehd-audio-1080.webm,segment_template=livehd-audio-1080-\$Number\$.webm \
in=pipe1,stream=video,init_segment=livehd-video-1080.webm,template=livehd-video-1080-\$Number\$.webm \
in=pipe2,stream=audio,init_segment=livehd-audio-720.webm,segment_template=livehd-audio-720-\$Number\$.webm \
in=pipe2,stream=video,init_segment=livehd-video-720.webm,template=livehd-video-720-\$Number\$.webm \
in=pipe3,stream=audio,init_segment=livehd-audio-360.webm,segment_template=livehd-audio-360-\$Number\$.webm \
in=pipe3,stream=video,init_segment=livehd-video-360.webm,template=livehd-video-360-\$Number\$.webm \
--mpd_output livehd.mpd --dump_stream_info --min_buffer_time=10 --time_shift_buffer_depth=300 \
--segment_duration=3 --io_block_size 65536