首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >( ffmpeg )从给定的VP9示例到.mp4或.webm容器的VP9 Vaapi编码

( ffmpeg )从给定的VP9示例到.mp4或.webm容器的VP9 Vaapi编码
EN

Stack Overflow用户
提问于 2019-03-05 16:21:17
回答 1查看 6.1K关注 0票数 5

我正在尝试实现vp9硬件加速编码过程。我遵循了ffmpeg官方github的例子(encode.c)。

但是,给定的示例只将一个.yuv文件保存到.h264文件,我希望将框架保存到.mp4或.webm容器中。具备控制质量等能力。

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

我能够将所有的5秒帧从我的实时提要保存到一个.mp4或.webm文件中,但是它们不能被正确地播放(更准确地说:继续加载,然后我打开)。

官方网站的例子的结果:

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

编辑:结果

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-03-07 05:12:24

您需要直接使用FFmpeg,如果您在B帧编码器中启用B帧,您可以选择在同一个命令行中添加超框架重新排序 位流过滤器

示例:

代码语言:javascript
复制
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

根据需要调整输入和输出路径/urls。

此命令所做的工作:

它将通过mp4创建5秒长的段穆克塞段。请参阅movflags=+faststart的使用情况,以及如何通过上面的-segment_format_options标志将其作为格式选项传递给底层mp4 muxer。

段的长度可能不是完全5秒长,因为每个段开始(被切割)(用)一个关键帧。

但是,我不建议在该编码器中启用B帧,因为这些比特流过滤器具有其他不想要的效果,如与编码器的速率控制混在一起触发像这样的虫子。这在生产环境中是不可取的。这就是为什么下面的脚本没有启用该选项,相反,我们直接在编码器选项中定义了一个设置速率控制模式。

如果您需要利用VAAPI的1:N编码,请使用以下代码段:

  1. 如果需要去隔行,请调用deinterlace_vaapi过滤器:
代码语言:javascript
复制
    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. 无隔行的:
代码语言:javascript
复制
    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. 使用英特尔的QuickSync (支持的平台):

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

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

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

(c)。默认情况下,IVF头将插入到MSDK中,但FFmpeg不需要它,默认情况下仍然是禁用的。

见下面的例子:

  1. 如果需要去隔行,请调用vpp_qsv过滤器:
代码语言:javascript
复制
    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. 无隔行的:
代码语言:javascript
复制
    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选项设置为4的async_depth,这大大提高了使用scale_qsvdeinterlace_qsv的代码性能。参见FFmpeg的git上的此承诺

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

用于派生上面代码片段的公式:

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

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

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

分辨率阶梯使用:640 p,480 p和360 p 16:9,见链接。根据需要调整这一点。

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

测试并汇报。

当前观测:

在我的系统中,我可以使用VP9对多达5个流进行实时编码,使用苹果推荐的HLS HEVC编码分辨率和比特率作为基准。请看下面关于系统负载的图片,等等。

平台详细信息:

我在一个咖啡湖系统中,使用i965驱动程序来处理这个工作流:

代码语言:javascript
复制
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构建信息:

代码语言:javascript
复制
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

以及印西的产出:

代码语言:javascript
复制
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。这同样适用于Ubuntu18.04LTS上的图形驱动程序栈。FFmpeg是如图所示的这里,因为这台笔记本电脑通过擎天柱启用了NVIDIA+、Intel、GPU。这样,我就可以根据需要访问VAAPI、QuickSync和NVENC hwaccels。您的里程可能会不同的,即使我们的硬件是相同的。

参考资料:

  1. 请参阅编码器选项,包括支持的速率控制方法:
代码语言:javascript
复制
ffmpeg -h encoder=vp9_vaapi
  1. 请参阅deinterlace_vaapi筛选器使用选项:
代码语言:javascript
复制
ffmpeg -h filter=deinterlace_vaapi
  1. 关于vpp_qsv过滤器的使用情况,请参见:
代码语言:javascript
复制
ffmpeg -h filter=vpp_qsv

例如,如果您希望从去隔行器输出字段速率输出而不是帧速率输出,则可以将rate=field选项传递给它:

代码语言:javascript
复制
-vf=vaapi_deinterlace=rate=field

例如,这个特性与支持MBAFF的编码器绑定在一起。其他的,如FFmpeg、没有实现这一点中基于NVENC的(在编写时)。

在FFmpeg:上取得进展的技巧

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

例如,您将看到,在上面的片段中,我们只调用了一次去隔行器,然后通过split过滤器将其输出分割成独立的标量器。这样做是为了降低如果我们不止一次地调用除漆器将产生的开销,这将是浪费。

警告:

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55007246

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档