【问题标题】:(FFmpeg) VP9 Vaapi encoding to a .mp4 or .webm container from given official ffmpeg example(FFmpeg) 给定官方 ffmpeg 示例的 .mp4 或 .webm 容器的 VP9 Vaapi 编码
【发布时间】:2019-07-27 04:22:42
【问题描述】:

我正在尝试实现 vp9 硬件加速编码过程。我按照ffmpeg官方github的例子(Here -> vaapi_encode.c)。

但给出的示例仅将 .yuv 文件保存到 .h264 文件,我想将帧保存到 .mp4 或 .webm 容器。并具备质量控制能力等。

我不是从文件中读取帧,而是从实时提要中收集帧。当从实时提要中获得完整的 5 秒帧时,使用 vp9_vaapi 将这些帧编码为 5 秒 .mp4 文件。

我可以将实时源中的所有 5 秒帧保存到 .mp4 或 .webm 文件,但它们无法正确播放(更准确地说:继续加载,然后我打开)。

官网示例结果:

cpu编码的vp9 .mp4文件结果:

编辑: 结果

【问题讨论】:

    标签: encoding ffmpeg mp4 hardware-acceleration vaapi


    【解决方案1】:

    您将需要直接使用 FFmpeg,如果您在 vp9_vaapi 编码器中启用 B 帧,您可以选择在同一命令行中添加 vp9_superframevp9_raw_reorder bitstream filters

    示例:

    ffmpeg -threads 4 -vaapi_device /dev/dri/renderD128 \
    -hwaccel vaapi -hwaccel_output_format vaapi \
    -i http://server:port \
    -c:v vp9_vaapi -global_quality 50 -bf 1 \
    -bsf:v vp9_raw_reorder,vp9_superframe \
    -f segment -segment_time 5 -segment_format_options movflags=+faststart output%03d.mp4
    

    根据需要调整您的输入和输出路径/网址。

    此命令的作用:

    它将通过segment muxer 创建 5 秒长的 mp4 片段。 查看 movflags=+faststart 的用法,以及它是如何通过上面的 -segment_format_options 标志作为格式选项传递给底层 mp4 多路复用器的。

    片段长度可能不完全是 5 秒长,因为每个片段都开始(被剪切)(带有)一个关键帧。

    但是,我不建议在该编码器中启用 B 帧,因为这些比特流过滤器会产生其他不良影响,例如 mucking around with the encoder's rate controltriggering bugs like this one。这在生产环境中是不可取的。这就是为什么下面的脚本没有启用该选项的原因,而是直接在编码器选项中定义了设置速率控制模式。

    如果您需要利用 VAAPI 的 1:N 编码,请使用这些 sn-ps:

    1. 如果您需要去隔行扫描,请调用deinterlace_vaapi 过滤器:
        ffmpeg -loglevel debug -threads 4 \
        -init_hw_device vaapi=va:/dev/dri/renderD128 -hwaccel vaapi \
        -hwaccel_device va -filter_hw_device va \
        -hwaccel_output_format vaapi \
        -i 'http://server:port' \
        -filter_complex "[0:v]deinterlace_vaapi,split=3[n0][n1][n2]; \
        [n0]scale_vaapi=1152:648[v0]; \
        [n1]scale_vaapi=848:480[v1];
        [n2]scale_vaapi=640:360[v2]" \
        -b:v:0 2250k -maxrate:v:0 2250k -bufsize:v:0 360k -c:v:0 vp9_vaapi -g:v:0 50 -r:v:0 25 -rc_mode:v:0 2 \
        -b:v:1 1750k -maxrate:v:1 1750k -bufsize:v:1 280k -c:v:1 vp9_vaapi -g:v:1 50 -r:v:1 25 -rc_mode:v:1 2 \
        -b:v:2 1000k -maxrate:v:2 1000k -bufsize:v:2 160k -c:v:2 vp9_vaapi -g:v:2 50 -r:v:2 25 -rc_mode:v:2 2 \
        -c:a aac -b:a 128k -ar 48000 -ac 2 \
        -flags -global_header -f tee -use_fifo 1 \
        -map "[v0]" -map "[v1]" -map "[v2]" -map 0:a \
        "[select=\'v:0,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path0/output%03d.mp4| \
         [select=\'v:1,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path1/output%03d.mp4| \
         [select=\'v:2,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path2/output%03d.mp4"
    
    1. 没有去隔行:
        ffmpeg -loglevel debug -threads 4 \
        -init_hw_device vaapi=va:/dev/dri/renderD128 -hwaccel vaapi \
        -hwaccel_device va -filter_hw_device va -hwaccel_output_format vaapi \
        -i 'http://server:port' \
        -filter_complex "[0:v]split=3[n0][n1][n2]; \
        [n0]scale_vaapi=1152:648[v0]; \
        [n1]scale_vaapi=848:480[v1];
        [n2]scale_vaapi=640:360[v2]" \
        -b:v:0 2250k -maxrate:v:0 2250k -bufsize:v:0 2250k -c:v:0 vp9_vaapi -g:v:0 50 -r:v:0 25 -rc_mode:v:0 2  \
        -b:v:1 1750k -maxrate:v:1 1750k -bufsize:v:1 1750k -c:v:1 vp9_vaapi -g:v:1 50 -r:v:1 25 -rc_mode:v:1 2  \
        -b:v:2 1000k -maxrate:v:2 1000k -bufsize:v:2 1000k -c:v:2 vp9_vaapi -g:v:2 50 -r:v:2 25 -rc_mode:v:2 2  \
        -c:a aac -b:a 128k -ar 48000 -ac 2 \
        -flags -global_header -f tee -use_fifo 1 \
        -map "[v0]" -map "[v1]" -map "[v2]" -map 0:a \
        "[select=\'v:0,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path0/output%03d.mp4| \
         [select=\'v:1,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path1/output%03d.mp4| \
         [select=\'v:2,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path2/output%03d.mp4"
    
    1. 使用 Intel 的 QuickSync(在支持的平台上):

    在 Intel Icelake 及更高版本上,您可以使用具有以下已知限制的 vp9_qsv 编码器包装器(目前):

    (一)。您必须启用low_power mode,因为目前iHD 驱动程序只公开了 VDENC 解码路径。

    (b)。 MSDK 不支持编码 option1 和 extra_data。

    (c)。 IVF头默认会插入到MSDK中,但FFmpeg不需要,默认保持禁用状态。

    请看下面的例子:

    1. 如果您需要去隔行扫描,请调用vpp_qsv 过滤器:
        ffmpeg -nostdin -y -fflags +genpts \
        -init_hw_device vaapi=va:/dev/dri/renderD128,driver=iHD \
        -filter_hw_device va -hwaccel vaapi -hwaccel_output_format vaapi
        -threads 4 -vsync 1 -async 1 \
        -i 'http://server:port' \
        -filter_complex "[0:v]hwmap=derive_device=qsv,format=qsv,vpp_qsv=deinterlace=2:async_depth=4,split[n0][n1][n2]; \
        [n0]vpp_qsv=w=1152:h=648:async_depth=4[v0]; \
        [n1]vpp_qsv=w=848:h=480:async_depth=4[v1];
        [n2]vpp_qsv=w=640:h=360:async_depth=4[v2]" \
        -b:v:0 2250k -maxrate:v:0 2250k -bufsize:v:0 360k -c:v:0 vp9_qsv -g:v:0 50 -r:v:0 25 -low_power:v:0 2 \
        -b:v:1 1750k -maxrate:v:1 1750k -bufsize:v:1 280k -c:v:1 vp9_qsv -g:v:1 50 -r:v:1 25 -low_power:v:1 2 \
        -b:v:2 1000k -maxrate:v:2 1000k -bufsize:v:2 160k -c:v:2 vp9_qsv -g:v:2 50 -r:v:2 25 -low_power:v:2 2 \
        -c:a aac -b:a 128k -ar 48000 -ac 2 \
        -flags -global_header -f tee -use_fifo 1 \
        -map "[v0]" -map "[v1]" -map "[v2]" -map 0:a \
        "[select=\'v:0,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path0/output%03d.mp4| \
         [select=\'v:1,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path1/output%03d.mp4| \
         [select=\'v:2,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path2/output%03d.mp4"
    
    1. 没有去隔行:
        ffmpeg -nostdin -y -fflags +genpts \
        -init_hw_device vaapi=va:/dev/dri/renderD128,driver=iHD \
        -filter_hw_device va -hwaccel vaapi -hwaccel_output_format vaapi
        -threads 4 -vsync 1 -async 1 \
        -i 'http://server:port' \
        -filter_complex "[0:v]hwmap=derive_device=qsv,format=qsv,split=3[n0][n1][n2]; \
        [n0]vpp_qsv=w=1152:h=648:async_depth=4[v0]; \
        [n1]vpp_qsv=w=848:h=480:async_depth=4[v1];
        [n2]vpp_qsv=w=640:h=360:async_depth=4[v2]" \
        -b:v:0 2250k -maxrate:v:0 2250k -bufsize:v:0 2250k -c:v:0 vp9_qsv -g:v:0 50 -r:v:0 25 -low_power:v:0 2  \
        -b:v:1 1750k -maxrate:v:1 1750k -bufsize:v:1 1750k -c:v:1 vp9_qsv -g:v:1 50 -r:v:1 25 -low_power:v:1 2  \
        -b:v:2 1000k -maxrate:v:2 1000k -bufsize:v:2 1000k -c:v:2 vp9_qsv -g:v:2 50 -r:v:2 25 -low_power:v:2 2  \
        -c:a aac -b:a 128k -ar 48000 -ac 2 \
        -flags -global_header -f tee -use_fifo 1 \
        -map "[v0]" -map "[v1]" -map "[v2]" -map 0:a \
        "[select=\'v:0,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path0/output%03d.mp4| \
         [select=\'v:1,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path1/output%03d.mp4| \
         [select=\'v:2,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path2/output%03d.mp4"
    

    请注意,我们使用vpp_qsv filter 并将async_depth 选项设置为4。与使用scale_qsvdeinterlace_qsv 相比,这大大提高了转码性能。请参阅 FFmpeg 的 git 上的 this commit

    注意:如果您使用 QuickSync 路径,请注意如果您系统上的 Media SDK 库支持,则默认启用 MFE(多帧编码模式)。

    用于推导上述 sn-p 的公式:

    最佳 bufsize:v = 目标比特率(-b:v 值)

    将 GOP 大小设置为:2 * fps(GOP 间隔设置为 2 秒)。

    我们通过-threads:v 限制视频编码器的线程数,以防止 VBV 溢出。

    使用的分辨率阶梯:16:9 中的 640p、480p 和 360p,请参阅this 链接。 根据需要进行调整。

    根据需要替换上述变量($output_path{0-2}、输入等)。

    测试并报告。

    当前观察:

    在我的系统上,我可以使用Apple's recommended resolutions and bit-rates for HEVC encoding for HLS 作为基准,使用 VP9 实时编码多达 5 个流。系统负载等见下图。

    平台详情:

    我在 Coffee-lake 系统上,为此工作流使用 i965 驱动程序:

    libva info: VA-API version 1.5.0
    libva info: va_getDriverName() returns 0
    libva info: User requested driver 'i965'
    libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
    libva info: Found init function __vaDriverInit_1_5
    libva info: va_openDriver() returns 0
    vainfo: VA-API version: 1.5 (libva 2.4.0.pre1)
    vainfo: Driver version: Intel i965 driver for Intel(R) Coffee Lake - 2.4.0.pre1 (2.3.0-11-g881e67a)
    vainfo: Supported profile and entrypoints
          VAProfileMPEG2Simple            : VAEntrypointVLD
          VAProfileMPEG2Simple            : VAEntrypointEncSlice
          VAProfileMPEG2Main              : VAEntrypointVLD
          VAProfileMPEG2Main              : VAEntrypointEncSlice
          VAProfileH264ConstrainedBaseline: VAEntrypointVLD
          VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
          VAProfileH264ConstrainedBaseline: VAEntrypointEncSliceLP
          VAProfileH264Main               : VAEntrypointVLD
          VAProfileH264Main               : VAEntrypointEncSlice
          VAProfileH264Main               : VAEntrypointEncSliceLP
          VAProfileH264High               : VAEntrypointVLD
          VAProfileH264High               : VAEntrypointEncSlice
          VAProfileH264High               : VAEntrypointEncSliceLP
          VAProfileH264MultiviewHigh      : VAEntrypointVLD
          VAProfileH264MultiviewHigh      : VAEntrypointEncSlice
          VAProfileH264StereoHigh         : VAEntrypointVLD
          VAProfileH264StereoHigh         : VAEntrypointEncSlice
          VAProfileVC1Simple              : VAEntrypointVLD
          VAProfileVC1Main                : VAEntrypointVLD
          VAProfileVC1Advanced            : VAEntrypointVLD
          VAProfileNone                   : VAEntrypointVideoProc
          VAProfileJPEGBaseline           : VAEntrypointVLD
          VAProfileJPEGBaseline           : VAEntrypointEncPicture
          VAProfileVP8Version0_3          : VAEntrypointVLD
          VAProfileVP8Version0_3          : VAEntrypointEncSlice
          VAProfileHEVCMain               : VAEntrypointVLD
          VAProfileHEVCMain               : VAEntrypointEncSlice
          VAProfileHEVCMain10             : VAEntrypointVLD
          VAProfileHEVCMain10             : VAEntrypointEncSlice
          VAProfileVP9Profile0            : VAEntrypointVLD
          VAProfileVP9Profile0            : VAEntrypointEncSlice
          VAProfileVP9Profile2            : VAEntrypointVLD
    
    

    我的 ffmpeg 构建信息:

    ffmpeg -buildconf
    ffmpeg version N-93308-g1144d5c96d Copyright (c) 2000-2019 the FFmpeg developers
      built with gcc 7 (Ubuntu 7.3.0-27ubuntu1~18.04)
      configuration: --pkg-config-flags=--static --prefix=/home/brainiarc7/bin --bindir=/home/brainiarc7/bin --extra-cflags=-I/home/brainiarc7/bin/include --extra-ldflags=-L/home/brainiarc7/bin/lib --enable-cuda-nvcc --enable-cuvid --enable-libnpp --extra-cflags=-I/usr/local/cuda/include/ --extra-ldflags=-L/usr/local/cuda/lib64/ --enable-nvenc --extra-cflags=-I/opt/intel/mediasdk/include --extra-ldflags=-L/opt/intel/mediasdk/lib --extra-ldflags=-L/opt/intel/mediasdk/plugins --enable-libmfx --enable-libass --enable-vaapi --disable-debug --enable-libvorbis --enable-libvpx --enable-libdrm --enable-opencl --enable-gpl --cpu=native --enable-opengl --enable-libfdk-aac --enable-libx265 --enable-openssl --extra-libs='-lpthread -lm' --enable-nonfree
      libavutil      56. 26.100 / 56. 26.100
      libavcodec     58. 47.103 / 58. 47.103
      libavformat    58. 26.101 / 58. 26.101
      libavdevice    58.  6.101 / 58.  6.101
      libavfilter     7. 48.100 /  7. 48.100
      libswscale      5.  4.100 /  5.  4.100
      libswresample   3.  4.100 /  3.  4.100
      libpostproc    55.  4.100 / 55.  4.100
    
      configuration:
        --pkg-config-flags=--static
        --prefix=/home/brainiarc7/bin
        --bindir=/home/brainiarc7/bin
        --extra-cflags=-I/home/brainiarc7/bin/include
        --extra-ldflags=-L/home/brainiarc7/bin/lib
        --enable-cuda-nvcc
        --enable-cuvid
        --enable-libnpp
        --extra-cflags=-I/usr/local/cuda/include/
        --extra-ldflags=-L/usr/local/cuda/lib64/
        --enable-nvenc
        --extra-cflags=-I/opt/intel/mediasdk/include
        --extra-ldflags=-L/opt/intel/mediasdk/lib
        --extra-ldflags=-L/opt/intel/mediasdk/plugins
        --enable-libmfx
        --enable-libass
        --enable-vaapi
        --disable-debug
        --enable-libvorbis
        --enable-libvpx
        --enable-libdrm
        --enable-opencl
        --enable-gpl
        --cpu=native
        --enable-opengl
        --enable-libfdk-aac
        --enable-libx265
        --enable-openssl
        --extra-libs='-lpthread -lm'
        --enable-nonfree
    
    

    inxi 的输出:

    inxi -F
    System:    Host: cavaliere Kernel: 5.0.0 x86_64 bits: 64 Desktop: Gnome 3.28.3 Distro: Ubuntu 18.04.2 LTS
    Machine:   Device: laptop System: ASUSTeK product: Zephyrus M GM501GS v: 1.0 serial: N/A
               Mobo: ASUSTeK model: GM501GS v: 1.0 serial: N/A
               UEFI: American Megatrends v: GM501GS.308 date: 10/01/2018
    Battery    BAT0: charge: 49.3 Wh 100.0% condition: 49.3/55.0 Wh (90%)
    CPU:       6 core Intel Core i7-8750H (-MT-MCP-) cache: 9216 KB
               clock speeds: max: 4100 MHz 1: 2594 MHz 2: 3197 MHz 3: 3633 MHz 4: 3514 MHz 5: 3582 MHz 6: 3338 MHz
               7: 3655 MHz 8: 3684 MHz 9: 1793 MHz 10: 3651 MHz 11: 3710 MHz 12: 3662 MHz
    Graphics:  Card-1: Intel Device 3e9b
               Card-2: NVIDIA GP104M [GeForce GTX 1070 Mobile]
               Display Server: x11 (X.Org 1.19.6 ) drivers: modesetting,nvidia (unloaded: fbdev,vesa,nouveau)
               Resolution: 1920x1080@144.03hz
               OpenGL: renderer: GeForce GTX 1070/PCIe/SSE2 version: 4.6.0 NVIDIA 418.43
    Audio:     Card-1 Intel Cannon Lake PCH cAVS driver: snd_hda_intel Sound: ALSA v: k5.0.0
               Card-2 NVIDIA GP104 High Definition Audio Controller driver: snd_hda_intel
               Card-3 Kingston driver: USB Audio
    Network:   Card: Intel Wireless-AC 9560 [Jefferson Peak] driver: iwlwifi
               IF: wlo1 state: up mac: (redacted)
    Drives:    HDD Total Size: 3050.6GB (94.5% used)
               ID-1: /dev/nvme0n1 model: Samsung_SSD_960_EVO_1TB size: 1000.2GB
               ID-2: /dev/sda model: Crucial_CT2050MX size: 2050.4GB
    Partition: ID-1: / size: 246G used: 217G (94%) fs: ext4 dev: /dev/nvme0n1p5
               ID-2: swap-1 size: 8.59GB used: 0.00GB (0%) fs: swap dev: /dev/nvme0n1p6
    RAID:      No RAID devices: /proc/mdstat, md_mod kernel module present
    Sensors:   System Temperatures: cpu: 64.0C mobo: N/A gpu: 61C
               Fan Speeds (in rpm): cpu: N/A
    Info:      Processes: 412 Uptime: 3:32 Memory: 4411.3/32015.5MB Client: Shell (bash) inxi: 2.3.56 
    
    

    为什么要包含最后一点:

    我正在运行迄今为止最新的 Linux 内核 5.0 版。 这同样适用于 Ubuntu 18.04LTS 上的图形驱动程序堆栈。 FFmpeg 的构建如图here 所示,因为这台笔记本电脑通过 Optimus 启用了 NVIDIA+ Intel GPU。这样,我可以根据需要使用 VAAPI、QuickSync 和 NVENC hwaccels。 即使我们的硬件相同,您的里程也可能会有所不同

    参考资料:

    1. 查看编码器选项,包括支持的速率控制方法:
    ffmpeg -h encoder=vp9_vaapi
    
    1. 查看 deinterlace_vaapi 过滤器使用选项:
    ffmpeg -h filter=deinterlace_vaapi
    
    1. 关于vpp_qsv 过滤器的使用,请参阅:
    ffmpeg -h filter=vpp_qsv
    

    例如,如果您想要场速率输出而不是去隔行器的帧速率输出,则可以将 rate=field 选项传递给它:

    -vf=vaapi_deinterlace=rate=field
    

    例如,此功能与支持 MBAFF 的编码器相关联。其他的,例如 FFmpeg 中基于 NVENC 的,do not have this implemented(截至撰写本文时)。

    使用 FFmpeg 取得成功的提示:

    在可能的情况下,推断内置文档,如上面所示的示例。 他们可以通过了解过滤器链接和编码器初始化的工作原理、不受支持的功能等以及对性能的影响来发现您可以避免的潜在陷阱。

    例如,您会在上面的 sn-ps 中看到,我们只调用一次去隔行器,然后通过 split 过滤器将其输出拆分为单独的缩放器。这样做是为了降低如果我们多次调用去隔行器会产生的开销,这将是一种浪费。

    警告:

    请注意,SDK 至少需要 2 个线程来防止死锁,请参阅 this 代码块。这就是我们在 ffmpeg 中设置-threads 4 的原因。

    【讨论】:

    • 直接使用 FFmpeg 真是个好消息。您的命令行需要 .mp4 输入,您知道如何直接使用 FFmpeg 将直播流(网络摄像机)每 5 秒编码为 5 秒视频吗?
    • 是的。但是,请注意可能的 GPU 挂起,尤其是如果您使用的是较旧的 Linux 内核。我已经能够在 kabylake 上以比实时性能更快的速度编码多达 8 个 H.264/AVC 流,请参阅 gist.github.com/Brainiarc7/4f831867f8e55d35cbcb527e15f9f116 示例
    • 据我所知,只有开源 VAAPI 驱动程序 (i965) 支持 VP9。为 Media SDK (iHD) 打包的专有驱动程序很可能不支持 VP9 编码。使用选定的驱动程序运行 vainfo 和过滤 Slice (vainfo | grep Slice) 应该会显示支持的内容。让我生成一个具有请求功能的 ffmpeg sn-p。
    • 可能是这种情况,具体取决于您调用 ffmpeg 的方式以及系统上的软件堆栈。例如,旧内核的性能肯定会比新内核差得多。
    • 感谢信息更新,将定义。测试两个内核之间的性能差异。你是 FFmpeg 的神
    猜你喜欢
    • 2021-10-03
    • 2020-11-23
    • 2018-07-01
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多