缘起
FFmpeg是一个非常强大的音视频处理工具,可以用来剪辑、转码、合并、分离、提取视频音频等等。FFmpeg是一个自由开源软件,最初由法国程序员法布里斯·贝拉(Fabrice Bellard)发起,现在由米夏埃尔·尼德迈尔(Michael Niedermayer)维护。目前市面上的很多播放器、视频剪辑软件、转码软件,比如 Blender,Kodi, Plex, Shotcut, VLC media playe, YouTube等,都是基于FFmpeg的。当然,也有很多软件使用了FFmpeg的代码,但并未遵守FFmpeg的开源协议,被钉在了“FFmpeg耻辱柱”上。
FFmpeg是一个命令行工具,使用起来稍有些复杂,但功能非常强大。我只用到过几个简单的功能,比如视频剪切、合并、调整分辨率、转码,视频加速、慢放,音视频分离。但我之前一直都只用CPU来处理,现在电脑上有了显卡,就想使用GPU来加速。这确实费了我一点儿功夫,这里就来总结记录一下。
这是“Nvidia显卡”系列文章的第二篇,本系列文章主要记录如何使用Nvidia显卡,尤其是在Linux系统上使用Nvidia显卡。本系列的其他文章参见:
- Nvidia显卡(一):Ubuntu下的游戏、CUDA、深度学习、Docker等
- Nvidia显卡(三):Fedora下的游戏、CUDA、深度学习、Docker等
- Nvidia显卡(四):容器化配置Nvidia显卡的CUDA编程和深度学习环境
前提
- 电脑上有NVIDIA显卡
- Linux系统
从源码编译安装FFmpeg
我使用Ubuntu 22.04系统,之前我的FFmpeg是通过apt安装的,但是这个版本不支持GPU加速。所以我需要从源码编诹安装。如果你之前使用apt安装的FFmpeg,需要先卸载掉:
```bash
sudo apt-get remove ffmpeg
```
编译安装过程我参考了英伟达官方的文档。但遗憾的是,这个文档似乎有些过时了,直接按照文档的步骤编译安装,会出现一些问题。下面是我成功编译安装的步骤。
安装依赖
依赖主要有三方面:
-
英伟达的显卡驱动。这个请参考我之前的文章Ubuntu 22.04安装英伟达显卡驱动。
-
英伟达的编码接口库。使用下面的命令从源码编译安装。
1 2git clone https://github.com/FFmpeg/nv-codec-headers.git cd nv-codec-headers && sudo make install && cd – -
FFmpeg的依赖库。使用下面的命令安装。
1sudo 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
编译安装
-
下载FFmpeg源码。
1git clone https://git.ffmpeg.org/ffmpeg.git -
配置编译参数。
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是为了避免编译时出现如下错误:1nasm not found or too old. Please install/update nasm or use --disable-x86asm for a build without hand-optimized assembly.
如果上述命令执行没有问题,则可以继续编译。
-
-
编译。
1make -j8这里的
-j8是指使用8个线程并行编译,可以根据自己的CPU核心数来调整。 -
安装。
1sudo make install上述命令会把FFmpeg安装到
/usr/local/bin目录下。
问题解决
在按照上面步骤编译安装后,当我在命令行运行ffmpeg时,出现了如下错误:
|
|
这是因为FFmpeg的库文件没有正确链接,需要手动链接:
|
|
如果上述命令不能解决问题,这是因为FFmpeg在编译安装时把链接库安装到了/usr/local/lib目录下,而系统默认的链接库路径是/usr/lib。这时需要把/usr/local/lib添加到链接库路径中:
|
|
FFmpeg的基本使用
这里简单列举几个我使用过的命令:
-
视频剪切。
1ffmpeg -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:复制编码。
-
视频转码。
比如把mkv格式转为mp4格式。
1ffmpeg -i input.mkv -codec copy output.mp4-codec copy:复制编码。
-
视频加速或慢放。
1ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" output.mp4-vf "setpts=0.5*PTS":加速倍数。小于1表示加速,大于1表示减速。这里的0.5表示加速2倍。
-
视频分辨率调整。
1ffmpeg -i input.mp4 -vf scale=1920:1080 output.mp4-vf scale=1920:1080:目标分辨率。
-
音视频分离。
1 2ffmpeg -i input.mp4 -vn -acodec copy output.aac ffmpeg -i input.mp4 -an -vcodec copy output.mp4-vn:不包含视频。-acodec copy:复制音频编码。-an:不包含音频。-vcodec copy:复制视频编码。
-
视频合并
如果要合并的视频分辨率、帧率、编码等参数一致,且视频只有两个,可以使用下面的命令:
1ffmpeg -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协议来合并。1ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4-
-f concat:指定协议。 -
-safe 0:允许读取任意文件。 -
-i list.txt:视频列表文件。内容如下:1 2 3file 'input1.mp4' file 'input2.mp4' file 'input3.mp4' -
-c copy:复制编码。
使用GPU加速
使用GPU加速需要在编译时添加--enable-cuda-nvcc和--enable-libnpp参数。上面的编译安装步骤中已经添加了这两个参数。
使用GPU加速需要指定-hwaccel cuda参数。比如:
|
|
-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处理时,会对视频进行压缩,导致视频的清晰度下降。如果你想保持视频的清晰度,可以指定码率。
|
|
-b:v 20M:指定码率为20M。这里的20M是指20Mbps,可以根据自己的需求调整。
FFmpeg在使用GPU加速时默认优先考虑速度,而不是清晰度。如果你想保持视频的清晰度,还可以使用-preset slow参数来指定编码速度。
|
|
-preset slow:指定编码速度为slow。这里的slow是指慢速,处理的速度慢了,但清晰度会提高。
你也可以将上述两个参数结合起来使用。
|
|