Featured image of post 视频剪辑转码工具FFmpeg使用GPU加速

视频剪辑转码工具FFmpeg使用GPU加速

使用FFmpeg进行视频剪辑和转码,以及如何使用GPU加速

缘起

FFmpeg是一个非常强大的音视频处理工具,可以用来剪辑、转码、合并、分离、提取视频音频等等。FFmpeg是一个自由开源软件,最初由法国程序员法布里斯·贝拉(Fabrice Bellard)发起,现在由米夏埃尔·尼德迈尔(Michael Niedermayer)维护。目前市面上的很多播放器、视频剪辑软件、转码软件,比如 Blender,Kodi, Plex, Shotcut, VLC media playe, YouTube等,都是基于FFmpeg的。当然,也有很多软件使用了FFmpeg的代码,但并未遵守FFmpeg的开源协议,被钉在了“FFmpeg耻辱柱”上。

FFmpeg是一个命令行工具,使用起来稍有些复杂,但功能非常强大。我只用到过几个简单的功能,比如视频剪切、合并、调整分辨率、转码,视频加速、慢放,音视频分离。但我之前一直都只用CPU来处理,现在电脑上有了显卡,就想使用GPU来加速。这确实费了我一点儿功夫,这里就来总结记录一下。

前提

  • 电脑上有NVIDIA显卡
  • Linux系统

从源码编译安装FFmpeg

我使用Ubuntu 22.04系统,之前我的FFmpeg是通过apt安装的,但是这个版本不支持GPU加速。所以我需要从源码编诹安装。如果你之前使用apt安装的FFmpeg,需要先卸载掉:

```bash
sudo apt-get remove ffmpeg
```

编译安装过程我参考了英伟达官方的文档。但遗憾的是,这个文档似乎有些过时了,直接按照文档的步骤编译安装,会出现一些问题。下面是我成功编译安装的步骤。

安装依赖

依赖主要有三方面:

  1. 英伟达的显卡驱动。这个请参考我之前的文章Ubuntu 22.04安装英伟达显卡驱动

  2. 英伟达的编码接口库。使用下面的命令从源码编译安装。

    1
    2
    
    git clone https://github.com/FFmpeg/nv-codec-headers.git
    cd nv-codec-headers && sudo make install && cd
  3. FFmpeg的依赖库。使用下面的命令安装。

    1
    
    sudo apt-get install build-essential yasm cmake libtool libc6 libc6-dev unzip wget libnuma1 libnuma-devsudo apt-get install build-essential yasm cmake libtool libc6 libc6-dev unzip wget libnuma1 libnuma-dev
    

编译安装

  1. 下载FFmpeg源码。

    1
    
    git clone https://git.ffmpeg.org/ffmpeg.git
    
  2. 配置编译参数。

    1
    
    ./configure --enable-nonfree --enable-cuda-nvcc --enable-libnpp --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64 --disable-static --enable-shared --disable-x86asm
    
    • 这里的/usr/local/cuda是英伟达显卡驱动的安装路径,如果你的安装路径不同,请修改。

    • --enable-nonfree是为了支持非自由的编码器。

    • --enable-cuda-nvcc是为了支持CUDA加速。

    • --enable-libnpp是为了支持NPP加速。NPP是NVIDIA Performance Primitives的缩写,是英伟达提供的一套高性能图像和信号处理函数库,FFmpeg默认是不支持的。

    • --disable-x86asm是为了避免编译时出现如下错误:

      1
      
      nasm not found or too old. Please install/update nasm or use --disable-x86asm for a build without hand-optimized assembly.
      

    如果上述命令执行没有问题,则可以继续编译。

  3. 编译。

    1
    
    make -j8
    

    这里的-j8是指使用8个线程并行编译,可以根据自己的CPU核心数来调整。

  4. 安装。

    1
    
    sudo make install
    

    上述命令会把FFmpeg安装到/usr/local/bin目录下。

问题解决

在按照上面步骤编译安装后,当我在命令行运行ffmpeg时,出现了如下错误:

1
ffmpeg: error while loading shared libraries: libavdevice.so.61: cannot open shared object file: No such file or directory

这是因为FFmpeg的库文件没有正确链接,需要手动链接:

1
sudo ldconfig

如果上述命令不能解决问题,这是因为FFmpeg在编译安装时把链接库安装到了/usr/local/lib目录下,而系统默认的链接库路径是/usr/lib。这时需要把/usr/local/lib添加到链接库路径中:

1
2
sudo echo "/usr/local/lib" > /etc/ld.so.conf.d/ffmpeg.conf
sudo ldconfig

FFmpeg的基本使用

这里简单列举几个我使用过的命令:

  1. 视频剪切。

    1
    
    ffmpeg -i input.mp4 -ss 00:00:00 -t 00:00:10 -c copy output.mp4
    
    • -i input.mp4:输入文件。
    • -ss 00:00:00:开始时间。
    • -t 00:00:10:持续时间。
    • -c copy:复制编码。
  2. 视频转码。

    比如把mkv格式转为mp4格式。

    1
    
    ffmpeg -i input.mkv -codec copy output.mp4
    
    • -codec copy:复制编码。
  3. 视频加速或慢放。

    1
    
    ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" output.mp4
    
    • -vf "setpts=0.5*PTS":加速倍数。小于1表示加速,大于1表示减速。这里的0.5表示加速2倍。
  4. 视频分辨率调整。

    1
    
    ffmpeg -i input.mp4 -vf scale=1920:1080 output.mp4
    
    • -vf scale=1920:1080:目标分辨率。
  5. 音视频分离。

    1
    2
    
    ffmpeg -i input.mp4 -vn -acodec copy output.aac
    ffmpeg -i input.mp4 -an -vcodec copy output.mp4
    
    • -vn:不包含视频。
    • -acodec copy:复制音频编码。
    • -an:不包含音频。
    • -vcodec copy:复制视频编码。
  6. 视频合并

    如果要合并的视频分辨率、帧率、编码等参数一致,且视频只有两个,可以使用下面的命令:

    1
    
    ffmpeg -i input1.mp4 -i input2.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mp4
    
    • -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa]":合并视频和音频。

    如果要合并的视频数量较多,则推荐把视频列表写入一个文本文件,然后使用concat协议来合并。

    1
    
    ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4
    
    • -f concat:指定协议。

    • -safe 0:允许读取任意文件。

    • -i list.txt:视频列表文件。内容如下:

      1
      2
      3
      
      file 'input1.mp4'
      file 'input2.mp4'
      file 'input3.mp4'
      
    • -c copy:复制编码。

使用GPU加速

使用GPU加速需要在编译时添加--enable-cuda-nvcc--enable-libnpp参数。上面的编译安装步骤中已经添加了这两个参数。

使用GPU加速需要指定-hwaccel cuda参数。比如:

1
ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i input.mkv -c:v h264_nvenc -ss 0:00:00 -to 0:01:23 output.mp4
  • -hwaccel cuda:指定使用CUDA加速。
  • -hwaccel_output_format cuda:指定输出格式为CUDA。
  • -c:v h264_nvenc:指定使用NVIDIA的h264编码器。当然你也可以使用其他编码器,比如hevc_nvenc。若要查看支持的编码器,可以使用ffmpeg -h encoder=nvenc命令。

当然,上面介绍的那些命令也可以使用GPU加速,只需要添加-hwaccel cuda参数即可。

我的CPU是i5-9600K,显卡是英伟达的RTX 4060 Ti。只使用CPU时,处理一个分辨率为1920x1080的视频,CPU占用率约100%,处理速度约为每秒30帧。使用GPU加速后,GPU占用率约为33%,处理速度约为每秒500帧。可以看到,GPU加速后处理速度提升了约16倍。

清晰度问题

使用GPU加速后,视频的清晰度可能会有所下降。这是因为GPU加速时,FFmpeg会使用NPP库来处理图像,NPP库的处理精度可能不如CPU。

如果你分别用CPU和GPU处理同一个视频,然后对比两个视频的大小,会发现GPU处理的视频大小要小很多。例如,我用CPU剪切的一个视频大小为300MB,用GPU剪切同一个视频,大小只有50MB。

查看两个视频的码率,会发现GPU剪切的视频的码率远小于源视频的码率。这是因为GPU处理时,会对视频进行压缩,导致视频的清晰度下降。如果你想保持视频的清晰度,可以指定码率。

1
ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i input.mkv -c:v h264_nvenc -b:v 20M -ss 0:00:00 -to 0:01:23 output.mp4
  • -b:v 20M:指定码率为20M。这里的20M是指20Mbps,可以根据自己的需求调整。

FFmpeg在使用GPU加速时默认优先考虑速度,而不是清晰度。如果你想保持视频的清晰度,还可以使用-preset slow参数来指定编码速度。

1
ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i input.mkv -c:v h264_nvenc -preset slow -ss 0:00:00 -to 0:01:23 output.mp4
  • -preset slow:指定编码速度为slow。这里的slow是指慢速,处理的速度慢了,但清晰度会提高。

你也可以将上述两个参数结合起来使用。

1
ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i input.mkv -c:v h264_nvenc -b:v 20M -preset slow -ss 0:00:00 -to 0:01:23 output.mp4
comments powered by Disqus