目录
1.NVDIA概述
FFmpeg可通过Nvidia的GPU进行加速,其中高层接口是通过Video Codec SDK来实现GPU资源的调用。Video Codec SDK包含完整的的高性能工具、源码及文档,支持,可以运行在Windows和Linux系统之上。从软件上来说,SDK包含两类硬件加速接口,用于编码加速的NVENCODE API和用于解码加速的NVDECODE API(之前被称为NVCUVID API)。从硬件上来说,Nvidia GPU有一到多个编解码器(解码器又称硬件加速引擎),它们独立于CUDA核。从视频格式上来说,编码支持H.264、H.265、无损压缩,位深度支持8bit、10bit,色域空间支持YUV 4:4:4和4:2:0,分辨率支持最高8K;解码支持MPEG-2、VC1、VP8、VP9、H.264、H.265、无损压缩,位深度支持8 bit、10bit、12bit,色域空间支持YUV 4:2:0,分辨率支持最高8K。Video Codec SDK已经被集成在ffmpeg工程中,但是ffmpeg对编解码器配置参数较少,如果需要充分的发挥编解码器特性,还需要直接使用SDK进行编程。
2.FFmpeg集成到GPU
FFmpeg被许多项目使用,包括googlechrome和VLC播放器。通过配置FFmpeg将NVIDIA gpu用于视频编码和解码任务,您可以轻松地将NVIDIA硬件加速集成到这些应用程序中,GPU加速视频处理集成到最流行的开源多媒体工具中。
视频编码、解码和转码是FFmpeg最流行的应用之一。由于FFmpeg和libav社区的支持以及NVIDIA工程师的贡献,这两个工具现在都支持本机NVIDIA GPU硬件加速的视频编码和解码,通过整合NVIDIA视频编解码器SDK。
利用FFmpeg的音频编解码器、流muxing和RTP协议,FFmpeg与NVIDIA视频编解码器SDK的集成实现了高性能硬件加速的视频管道。
3.FFmpeg uses Video Codec SDK
FFmpeg支持由NVIDIA GPU上的视频硬件加速的以下功能:
- 支持h.264和hevc硬件加速编码; 支持h.264, hevc, VP9, VP8, MPEG2和MPEG4的硬件加速解码;
- 可设置跟视频编码质量相关的参数,如:preset, rate等;
- 可使用FFmpeg中的filters进行端对端1:n编码或1:n转码视频硬件加速通道;
- 能添加自己编写的高性能CUDA filters;
- 同时支持Windows和Linux support;
Nvidia编码器与CPU上的x264的性能对比与质量对比如下图所示,性能以每秒钟编码帧数为参考指标,质量以PSNR为参考指标。
可看出性能方面Nvidia编码器是x264的2~5倍,质量方面对于fast stream场景来说Nvidia编码器优于x264,高质量场景来说低于x264,但没有说明是哪款Nvidia的产品,以及对比测试的x264运行平台的CPU的型号及平台能力。下图可以看出对于1080P@30fps,NVENC可支持21路的编码或9路的高质量编码。
4.ffmpeg对NVIDIA GPU的编译步骤
- 下载FFmpeg源码 (https://git.FFmpeg.org/FFmpeg.git) 下载NVIDIA的最新Video Codec SDK 将NVIDIA的头文件复制到ffmpeg的编译环境中;
- 下载安装NVIDIA驱动(apt install nvidia-375)
- CUDA工具集
- 添加如下的configure命令(nv_sdk应包含cuda的库和头文件)
4.1configure命令
configure \
--enable-version3 \
--enable-libfdk-aac \
--enable-libmp3lame \
--enable-libx264 \
--enable-nvenc \
--extra-cflags=-I/root/workspace/Video_Codec_SDK_7.1.9/Samples/common/inc \
--extra-ldflags=-L/root/workspace/Video_Codec_SDK_7.1.9/Samples/common/lib/linux/x86_64 \
--enable-shared \
--enable-gpl \
--enable-postproc \
--enable-nonfree \
--enable-avfilter \
--enable-pthreads
4.2 make
运行make & make install
4.3 ffmpeg测试
运行ffmpeg -codecs|grep nvenc
显示一下信息说明
ffmpeg version 3.0.git Copyright (c) 2000-2016 the FFmpeg developers
built with gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.1) 20160609
configuration: --enable-version3 --enable-libfdk-aac --enable-libmp3lame --enable-libx264 --enable-nvenc --extra-cflags=-I/workspace/Video_Codec_SDK_7.1.9/Samples/common/inc --extra-ldflags=-L/workspace/Video_Codec_SDK_7.1.9/Samples/common/lib/linux/x86_64 --enable-shared --enable-gpl --enable-postproc --enable-nonfree --enable-avfilter --enable-pthreads
libavutil 55. 29.100 / 55. 29.100
libavcodec 57. 54.100 / 57. 54.100
libavformat 57. 48.100 / 57. 48.100
libavdevice 57. 0.102 / 57. 0.102
libavfilter 6. 57.100 / 6. 57.100
libswscale 4. 1.100 / 4. 1.100
libswresample 2. 1.100 / 2. 1.100
libpostproc 54. 0.100 / 54. 0.100
DEV.LS h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (encoders: libx264 libx264rgb h264_nvenc nvenc nvenc_h264 )
DEV.L. hevc H.265 / HEVC (High Efficiency Video Coding) (encoders: nvenc_hevc hevc_nvenc )
其中前缀含义如下:
前缀含义
D….. = Decoding supported
.E…. = Encoding supported
..V… = Video codec
..A… = Audio codec
..S… = Subtitle codec
…I.. = Intra frame-only codec
….L. = Lossy compression
…..S = Lossless compression
4.4 编解码器使用方法
h265编码测试
(1). ffmpeg -s 1920x1080 -pix_fmt yuv420p -i BQTerrace_1920x1080_60.yuv -vcodec hevc_nvenc -r 60 -y 2_60.265
(2). ffmpeg -s 1920x1080 -pix_fmt yuv420p -i BQTerrace_1920x1080_60.yuv -vcodec hevc_nvenc -r 30 -y 2_30.265
h264编码测试
(3). ffmpeg -s 1920x1080 -pix_fmt yuv420p -i BQTerrace_1920x1080_60.yuv -vcodec h264_nvenc -r 60 -y 2_60.264
(4). ffmpeg -s 1920x1080 -pix_fmt yuv420p -i BQTerrace_1920x1080_60.yuv -vcodec h264_nvenc -r 30 -y 2_30.264
h264转h265
(5). ffmpeg -i 1_60.264 -vcodec hevc_nvenc -r 60 -y 2_60_264to265.265
(6). ffmpeg -i 1_30.264 -vcodec hevc_nvenc -r 30 -y 2_30_264to265.265
h265转h264
(7). ffmpeg -i 1_60.265 -vcodec h264_nvenc -r 60 -y 2_60_265to264.264
(8). ffmpeg -i 1_30.265 -vcodec h264_nvenc -r 30 -y 2_30_265to264.264
4.5 程序开发使用方法
av_find_encoder_by_name(“h264_nvenc”);
av_find_encoder_by_name(“hevc_nvenc”);
5.源码分析
集成在ffmpeg框架内的视频编解码器需要定义一个AVCodec结构体包含(私有结构体AVClass、三个函数等)
5.1 h264部分
(1). 结构体(nvenc_h264.c)
AVCodec ff_h264_nvenc_encoder = {
.name = "h264_nvenc",
.long_name = NULL_IF_CONFIG_SMALL("NVIDIA NVENC H.264 encoder"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H264,
.init = ff_nvenc_encode_init, //初始化函数
.encode2 = ff_nvenc_encode_frame, //编码函数
.close = ff_nvenc_encode_close, //关闭函数
.priv_data_size = sizeof(NvencContext), //内部数据结构,见nvenc.h
.priv_class = &h264_nvenc_class, //私有结构体
.defaults = defaults,
.capabilities = AV_CODEC_CAP_DELAY,
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
.pix_fmts = ff_nvenc_pix_fmts,
};
static const AVClass h264_nvenc_class = {
.class_name = "h264_nvenc",
.item_name = av_default_item_name,
.option = options, //编码器选项参数在这个AVOption结构体中
.version = LIBAVUTIL_VERSION_INT,
};
处理函数(nvenc.c)
av_cold int ff_nvenc_encode_init(AVCodecContext *avctx)
{
NvencContext *ctx = avctx->priv_data; //读入私有结构体
...
//下面是一些nvenc的api
nvenc_load_libraries
nvenc_setup_device
nvenc_setup_encoder
nvenc_setup_surfaces
nvenc_setup_extradata
...
}
int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet)
{
...
if (frame) {
inSurf = get_free_frame(ctx); //来一帧
...
res = nvenc_upload_frame(avctx, frame, inSurf);//编一帧
...
}
}
av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
{
...
//一些free和destroy的工作
}
5.2h265部分
(1). 结构体(nvenc_hevc.c)
AVCodec ff_hevc_nvenc_encoder = {
.name = "hevc_nvenc",
.long_name = NULL_IF_CONFIG_SMALL("NVIDIA NVENC hevc encoder"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_HEVC,
.init = ff_nvenc_encode_init, //初始化函数
.encode2 = ff_nvenc_encode_frame, //编码函数
.close = ff_nvenc_encode_close, //关闭函数
.priv_data_size = sizeof(NvencContext), //内部数据结构,见nvenc.h
.priv_class = &hevc_nvenc_class, //私有结构体
.defaults = defaults,
.pix_fmts = ff_nvenc_pix_fmts,
.capabilities = AV_CODEC_CAP_DELAY,
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
};
static const AVClass hevc_nvenc_class = {
.class_name = "hevc_nvenc",
.item_name = av_default_item_name,
.option = options,//编码器选项参数在这个AVOption结构体中
.version = LIBAVUTIL_VERSION_INT,
};
(2) 处理函数(nvenc.c)
同h264的处理函数
参考文章:
https://www.cnblogs.com/wujianming-110117/p/13235658.html