使用 FFmpeg 通过 VP9 进行实时编码

编码参数

VP9 会提供一系列参数来优化实时编码。比特率模式中讨论了这些方面的一些广泛原则。

FFmpeg VP9 编码示例

下表介绍了针对 VP9 编码的示例 ffmpeg 调用的参数。

参数 说明
-quality realtime realtime 对于直播和速度超过 5 而言至关重要。
-speed 6 直播/实时编码应使用速度从 58 之间的数字。数字越小(56),说明质量越高,但占用的 CPU 越多。数字越大(78),画质会降低,但对于延迟较低的使用场景以及 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 最大 iframe 比特率 (pct)
-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 模式不支持实时视频所需的实时编码。如需了解详情,请参阅比特率模式

还建议您参阅有关 VOD 设置的随附文章,但要详细了解如何操控 VP9,但应重点关注 CBR。

提示和技巧

请记住,进行直播时,所有内容都被限制在 1 倍的最低实时编码速度(FFmpeg 会报告编码进度)。如果您的编码速度低于 1 倍,那么编码过程将不能跟上直播视频的输入,并且用户将需要缓冲,并且传输中断会导致直播在直播期间无法使用(尽管归档通常可以使用)。

编码参数的实际应用示例

下面显示了在搭载 Linux 的四核 i5 3.6Ghz 桌面设备上,各种帧尺寸的 CPU 利用率(25 fps):

目标解决时间 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.51x
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.27 倍
426x240 (240p) -r 30 -g 90 -s 426x240 -quality realtime -speed 8 -threads 2 -row-mt 1 -tile-columns 0 -frame-并行跟踪 0 -qmin 4 -qmax 48 -b:v 365k 约 66% 8.27x

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 vp9 \
  -b:a 128k -c:a libopus -f webm pipe1

提示和技巧

  • 请注意,我们将输出到 FIFO 管道 ("que1.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 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 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 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 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 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 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 vp9 -b:a 64k -c:a libopus -f webm pipe7

不过,上述完整集需要一个非常强大的 CPU,或者可能需要从硬件 GPU 分流(如一些芯片组越来越多提供)支持。Intel Kabylake(及更高版本)拥有完整的硬件编码管道。(请注意,Kabylake GPU 可以执行 8 位 VP9 编码,但不能执行 10 位编码)。

使用 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 发行版:OS: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 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 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 vp9 -b:a 128k -c:a libopus -f webm pipe3

请注意,-speed 设置的值非常高。这些设置是实验性的,会因机器而异

Shaka 软件包开销开销

封装不是占用大量 CPU 资源的 Activity。可以将 Shaka Packager 设置为监听所有输出,即使 FFmpeg 只分发了一部分也是如此。以下是在上文所述的机器上测试的打包器设置:

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