NVENC 视频编码器 API 编程指南 ( 中文转译 )
此为为对NVIDIA NvCodec12.1官方程序指南文档的中文翻译,笔者已经进行了校验,并结合实际开发中的云游戏之重点进行了重点提示。供各位开发人员进行参考。NVIDIA 文档需要结合实际开发场景进行自我参数修正,任何参数的调整都会对GPU、延迟、编码质量、兼容性产生影响,需要结合实际情况进行仔细的调整及优化。
基于 NVIDIA Kepler™ 和更高版本 GPU 架构的 NVIDIA® GPU 包含基于硬件的 H.264/HEVC/AV1 视频编码器(以下简称 NVENC)。NVENC 硬件采用 YUV/RGB 作为输入,并生成符合H.264/HEVC/AV1 标准的视频比特流。可以使用 NVIDIA 视频编解码器 SDK 中提供的 NVENCODE API 来访问 NVENC 硬件的编码功能。
本文档提供有关如何使用 SDK 中公开的 NVENCODE API 对 NVENC 进行编程的信息。NVENCODE API 公开了 Windows(Windows 10 及更高版本)和 Linux 上的编码功能。
希望开发人员了解 H.264/HEVC/AV1 视频编解码器并熟悉 Windows 和/或 Linux 开发环境。
NVENCODE API保证二进制向后兼容性(并且当向后兼容性被破坏时将进行显式引用)。这意味着使用旧版本已发布 API 编译的应用程序将继续在 NVIDIA 发布的未来驱动程序版本上运行。
开发人员可以创建一个客户端应用程序,调用nvEncodeAPI.dll(
Windows)或libnvidia-encode.so(
Linux) 公开的 NVENCODE API 函数。这些库作为 NVIDIA 显示驱动程序的一部分安装。LoadLibrary()
客户端应用程序可以在 Windows 或dlopen()
Linux 上使用时在运行时链接到这些库。
NVENCODE API 函数、结构和其他参数在 中公开nvEncodeAPI.h
,包含在 SDK 中。
NVENCODE API 是一个 C-API,并使用类似 C++ 接口的设计模式,其中应用程序创建 API 的实例并检索函数指针表以进一步与编码器交互。对于更喜欢具有现成代码的高级 API 的程序员,SDK 包含公开重要 API 函数的示例 C++ 类。
本文档的其余部分重点介绍nvEncodeAPI.h
. NVENCODE API 旨在接受原始视频帧(YUV 或 RGB 格式)并输出 H.264、HEVC 或 AV1 比特流。概括地说,编码流程包括以下步骤:
- 初始化编码器
- 设置所需的编码参数
- 分配输入/输出缓冲区
- 将帧复制到输入缓冲区并从输出缓冲区读取比特流。这可以同步(Windows 和 Linux)或异步(仅限 Windows 10 及更高版本)完成。
- 清理 - 释放所有分配的输入/输出缓冲区
- 关闭编码会话
这些步骤在文档的其余部分中进行了解释,并在视频编解码器 SDK 包中包含的示例应用程序中进行了演示。
打开编码会话
加载 DLL 或共享对象库后,客户端与 API 的第一次交互是调用NvEncodeAPICreateInstance
. NvEncodeAPICreateInstance
这将填充传递给实现接口中提供的功能的函数的指针的 输入/输出缓冲区。
加载NVENC接口后,客户端应首先调用NvEncOpenEncodeSessionEx
以打开编码会话。此函数返回一个编码会话句柄,该句柄必须用于当前会话中对 API 函数的所有后续调用。
初始化编码设备
DirectX 9
- 客户端应创建一个 DirectX 9 设备,其行为标志包括:
D3DCREATE_FPU_PRESERVE
和D3DCREATE_MULTITHREADED
D3DCREATE_HARDWARE_VERTEXPROCESSING
- 客户端应将指针传递给已创建设备的 IUnknown 接口(类型转换为
void *
)NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::device,
并设置NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::deviceType
为NV_ENC_DEVICE_TYPE_DIRECTX.
仅在 Windows 10 及更高版本的 Windows 操作系统上支持使用 DirectX 设备。
DirectX 10
- 客户端应将指针传递给已创建设备的 IUnknown 接口(类型转换为
void *
)NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::device,
并设置NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::deviceType
为NV_ENC_DEVICE_TYPE_DIRECTX.
仅在 Windows 10 及更高版本的 Windows 操作系统上支持使用 DirectX 设备。
DirectX 11
- 客户端应将指针传递给已创建设备的 IUnknown 接口(类型转换为
void *
)NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::device,
并设置NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::deviceType
为NV_ENC_DEVICE_TYPE_DIRECTX.
仅在 Windows 10 及更高版本的 Windows 操作系统上支持使用 DirectX 设备。
DirectX 12
- 客户端应将指针传递给已创建设备的 IUnknown 接口(类型转换为
void *
)NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::device,
并设置NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::deviceType
为NV_ENC_DEVICE_TYPE_DIRECTX.
仅在 Windows 10 20H1 及更高版本的 Windows 操作系统上支持使用 DirectX 12 设备。
不同的
- 客户端应创建浮动 CUDA 上下文,并将 CUDA 上下文句柄传递为
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::device,
并设置NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::deviceType
为NV_ENC_DEVICE_TYPE_CUDA.
Linux 和 Windows 10 及更高版本的 Windows 操作系统支持使用 CUDA 设备进行编码。
OpenGL
- 客户端应创建一个 OpenGL 上下文并使其成为调用 NVENCODE API 的线程的当前上下文(以便将上下文与调用 NVENCODE API 的线程/进程关联起来)。
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::device
必须NULL
且NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS::deviceType
必须设置为NV_ENC_DEVICE_TYPE_OPENGL.
仅在 Linux 上支持使用 OpenGL 设备类型进行编码。
选择编码器编解码器 GUID
客户端应选择一个编码 GUID,它代表所需的编解码器,用于按以下方式对视频序列进行编码:
- 客户端应调用
NvEncGetEncodeGUIDCount
以从 NVIDIA 视频编码器接口获取支持的编码器 GUID 的数量。 - 客户端应使用此计数来分配足够大的缓冲区来保存支持的编码器 GUIDS。
- 然后客户端应该调用
NvEncGetEncodeGUIDs
来填充此列表。
客户端应从此列表中选择与其要求匹配的 GUID,并将其用作encodeGUID
编码会话的其余部分。
编码器调整信息和预设配置
NVIDIA 编码器接口公开四种不同的调整信息枚举(高质量、低延迟、超低延迟和无损),以满足不同的视频编码用例。表 1显示了适用于一些流行用例的建议调整信息。
用例 | 调整信息参数的推荐值 |
---|---|
| 高质量 |
在高带宽信道中,可以容忍较大的偶尔帧大小 | 低延迟,带 CBR |
在带宽严格受限的信道中 | 超低延迟,带CBR |
| 无损 |
对于每个调整信息,提供了从 P1(最高性能)到 P7(最低性能)的七个预设,以控制性能/质量权衡。使用这些预设将自动设置所选调谐信息的所有相关编码参数。这是 API 公开的粗略控制级别。如果需要,可以调整预设中的特定属性/参数。这将在接下来的两小节中进行解释。
枚举预设 GUID
客户端可以枚举所选选项支持的预设 GUID,encodeGUID
如下所示:
- 客户端应调用
NvEncGetEncodePresetCount
以获取支持的编码器 GUID 的数量。 - 客户端应使用此计数来分配足够大的缓冲区来保存支持的预设 GUID。
- 然后客户端应该调用
NvEncGetEncodePresetGUIDs
来填充此列表。
选择编码器预设配置
如上所述,客户端可以presetGUID
直接使用 来配置编码会话。这将自动为硬件编码器设置适当的参数,以适应调整信息/预设组合所暗示的用例。如果需要,客户端可以选择微调预设中的编码器配置参数并覆盖预设默认值。从编程的角度来看,这种方法通常更方便,因为程序员只需要更改他/她感兴趣的配置参数,而其他所有内容都根据预设定义进行预先配置。
以下是获取预设编码配置并可选择更改选择配置参数的步骤:
- 按照上述枚举预设 GUID 部分中的说明枚举支持的预设。
- 选择要获取其编码配置的预设 GUID。
- 客户端应
NvEncGetEncodePresetConfigEx
使用选定的encodeGUID, tuningInfo
和presetGUID
作为输入进行调用 - 可以通过 检索所需的预设编码器配置
NV_ENC_PRESET_CONFIG::presetCfg
。 - 如果需要,可以使用相应的配置 API 覆盖默认编码器参数。
选择编码器配置文件
客户端可以指定要针对特定编码场景进行编码的配置文件。例如,编码视频以便在 iPhone/iPod 上播放、编码视频用于蓝光光盘创作等都需要某些配置文件。
客户端应执行以下操作来检索支持的编码器配置文件的列表:
- 客户端应调用
NvEncGetEncodeProfileGUIDCount
以从 NVIDIA 视频编码器接口获取支持的编码器 GUID 的数量。 - 客户端应使用此计数来分配足够大小的缓冲区来保存支持的编码配置文件 GUIDS。
- 然后客户端应该调用
NvEncGetEncodeProfileGUIDs
来填充此列表。
客户端应选择最符合要求的配置文件 GUID。
获取支持的输入格式列表
NVENCODE API 接受多种不同格式的输入帧,例如特定格式的 YUV 和 RGB,如下所示NV_ENC_BUFFER_FORMAT.
可以按如下方式检索支持的输入格式列表:
- 客户端应调用
NvEncGetInputFormatCount
以获取支持的输入格式的数量。 - 客户端应该使用此计数来分配缓冲区来保存支持的输入缓冲区格式的列表(它们是类型的列表元素
NV_ENC_BUFFER_FORMAT
)。 - 通过调用检索支持的输入缓冲区格式
NvEncGetInputFormats
。
客户端应选择此列表中列举的格式来创建输入缓冲区。
查询编码器能力
NVIDIA 视频编码器硬件已经发展了多代,每一代新一代 GPU 中都添加了许多功能。为了方便应用程序动态地了解系统上底层硬件编码器的能力,NVENCODE API 提供了专用的 API 来查询这些能力。在使用所需编码器功能之前查询该功能的支持是一个很好的编程习惯。
查询编码器功能可以按如下方式完成:
- 在参数中指定要查询的能力属性
NV_ENC_CAPS_PARAM::capsToQuery
。这应该是枚举的成员NV_ENC_CAPS
。 - 调用
NvEncGetEncodeCaps
以确定对所需属性的支持。
NV_ENC_CAPS
有关各个功能属性的解释, 请参阅 API 参考枚举定义。
初始化硬件编码器会话
客户端需要使用NvEncInitializeEncoder
通过编码器句柄指定的有效NV_ENC_INITIALIZE_PARAMS
编码器配置进行调用(成功打开编码会话后返回)
编码会话属性
配置编码会话属性
会话参数
结构中提供了输入格式、输出尺寸、显示宽高比、帧率、平均比特率等常用参数NV_ENC_INITIALIZE_PARAMS
。客户端应该使用此结构的实例作为 的输入NvEncInitalizeEncoder
。
客户端必须填充结构的以下成员NV_ENC_INITIALIZE_PARAMS
才能成功初始化编码会话:
NV_ENC_INITALIZE_PARAMS::encodeGUID
:客户端必须选择合适的编解码器 GUID,如选择编码器编解码器 GUID部分中所述。NV_ENC_INITIALIZE_PARAMS::encodeWidth
:客户端必须指定编码视频所需的宽度。NV_ENC_INITIALIZE_PARAMS::encodeHeight
:客户端必须指定编码视频所需的高度。
NV_ENC_INITALIZE_PARAMS::reportSliceOffsets
可用于启用切片偏移的报告。此功能需要NV_ENC_INITALIZE_PARAMS::enableEncodeAsync
设置为 0,并且不适用于 Kepler GPU 上基于 MB 和基于字节的切片。
高级编解码器级参数
处理编码比特流的参数(例如 GOP 长度、编码器配置文件、速率控制模式等)通过该结构公开NV_ENC_CONFIG
。客户端可以通过NV_ENC_INITIALIZE_PARAMS::encodeConfig as
下面的解释传递编解码器级别的参数。
高级编解码器特定参数
NV_ENC_CONFIG_H264
高级 H.264、HEVC 和 AV1 特定参数分别在结构、NV_ENC_CONFIG_HEVC
和中提供NV_ENC_CONFIG_AV1
。
客户端可以通过结构传递特定于编解码器的参数NV_ENC_CONFIG::encodeCodecConfig
。
完成编码的编解码器配置
使用预设进行高级控制
这是配置 NVIDIA 视频编码器接口的最简单方法,并且涉及客户端执行的最少设置步骤。这适用于客户端不需要微调任何编解码器级别参数的用例。
在这种情况下,客户端应遵循以下步骤:
- 客户端应指定会话参数,如会话参数部分中所述。
- 或者,客户端可以枚举并选择最适合当前用例的预设 GUID,如选择编码器编解码器 GUID部分中所述。然后,客户端应使用 传递选定的预设 GUID
NV_ENC_INITIALIZE_PARAMS::presetGUID
。这有助于 NVIDIA 视频编码器接口根据提供的encodeGUID, tuning info
和正确配置编码器会话presetGUID
。 - 客户端应将高级编解码器级参数指针设置
NV_ENC_INITIALIZE_PARAMS::encodeConfig::encodeCodecConfig
为 NULL。
通过覆盖预设参数进行更精细的控制
客户端可以选择在各个预设设置的参数之上编辑一些编码参数,如下所示:
- 客户端应指定会话参数,如会话参数部分中所述。
- 客户端应枚举并选择最适合当前用例的预设 GUID,如选择编码器编解码器 GUID部分中所述。客户端应检索预设编码配置,如选择编码器预设配置部分中所述。
- 客户端可能需要显式查询编码器支持某些功能或某些编码配置参数的能力。为此,客户应执行以下操作:
- 通过参数指定所需的能力属性
NV_ENC_CAPS_PARAM::capsToQuery
。这应该是枚举的成员NV_ENC_CAPS
。 - 调用
NvEncGetEncodeCaps
以确定对所需属性的支持。请参阅NV_ENC_CAPS
API 参考中的枚举定义以了解各个功能属性的解释。 - 选择所需的调整信息和预设 GUID,并获取相应的预设编码配置,如编码器调整信息和预设配置部分所述。
NV_ENC_CONFIG
然后,客户端可以根据其要求覆盖预设中的任何参数。NV_ENC_CONFIG
客户端应该使用指针传递微调的结构NV_ENC_INITIALIZE_PARAMS::encodeConfig::encodeCodecConfig
。- 另外,客户端还应该通过 传递选定的预设 GUID
NV_ENC_INITIALIZE_PARAMS::presetGUID
。这是为了允许 NVIDIA 视频编码器接口对与编码会话相关的内部参数进行编程,以确保编码输出符合客户端的请求。请注意,在此处传递预设的 GUID 不会覆盖微调的参数。
速率控制
NVENC支持多种速率控制模式,并通过结构体提供对与速率控制算法相关的各种参数的控制NV_ENC_INITIALIZE_PARAMS::encodeConfig::rcParams
。速率控制算法在NVENC固件中实现。
NVENC支持以下码率控制模式:
恒定比特率 (CBR)rateControlMode
:
通过设置来指定恒定比特率NV_ENC_PARAMS_RC_CBR
。在此模式下,仅averageBitRate
需要并被速率控制算法用作目标输出比特率。客户端可以控制 I 帧与 P 帧的比率,NV_ENC_RC_PARAMS::lowDelayKeyFrameScale
这有助于避免 I 帧最终生成大量比特时的通道拥塞。
设置NV_ENC_CONFIG_H264/ NV_ENC_CONFIG_HEVC::enableFillerDataInsertion = 1
或NV_ENC_CONFIG_AV1::enableBitstreamPadding = 1
防止需要严格遵守比特率。
可变比特率 (VBR):
可变比特率通过设置rateControlMode
指定NV_ENC_PARAMS_RC_VBR.
编码器尝试符合averageBitRate
长期的平均比特率,但maxBitRate
在编码期间不超过任何时间。在此模式下,averageBitRate
必须指定。如果maxBitRate
未指定,NVENC 会将其设置为内部确定的默认值。建议客户同时指定这两个参数maxBitRate
,averageBitRate
以便更好地控制。
Constant QPrateControlMode
:
此模式通过设置为来指定NV_ENC_PARAMS_RC_CONSTQP
。在此模式下,整个帧使用 中指定的 QP 进行编码NV_ENC_RC_PARAMS::constQP
。
目标质量rateControlMode
:
此模式通过在 中设置为 VBR 和所需的目标质量来指定targetQuality
。该目标质量的范围是0到51(Video Codec SDK 8.0及以上版本也支持小数值)。在此模式下,编码器尝试通过允许比特率根据 中指定的比特率参数而变化,从而保持每个帧的恒定质量maxBitRate
。因此,最终的平均比特率可能会根据正在编码的视频内容而显着变化。在此模式下,如果maxBitRate
设置,它将形成实际比特率的上限。因此,如果maxBitRate
设置得太低,比特率可能会受到限制,导致可能无法实现所需的目标质量。
多通道帧编码
当确定用于对帧进行编码的 QP 时,如果 NVENC 知道帧的整体复杂性,则有利于以最佳方式分配可用比特预算。在某些情况下,多通道编码也可能有助于捕获帧之间较大的运动。为此,NVENC 支持以下类型的多通道帧编码模式:
- 每帧编码 1 遍 (
NV_ENC_MULTI_PASS_DISABLED
) - 每帧 2 次通过,第一次通过为四分之一分辨率,第二次为全分辨率 (
NV_ENC_TWO_PASS_QUARTER_RESOLUTION
) - 每帧 2 遍,两次都是全分辨率 (
NV_ENC_TWO_PASS_FULL_RESOLUION
)。
在 1-pass 速率控制模式中,NVENC 估计宏块所需的 QP 并立即对宏块进行编码。在 2 遍速率控制模式中,NVENC 估计要编码的帧的复杂性并确定第一遍中帧中的比特分布。在第二遍中,NVENC 使用在第一遍中确定的分布对帧中的宏块进行编码。因此,通过 2-pass 速率控制模式,NVENC 可以在帧内更优化地分配比特,并且可以更接近目标比特率,特别是对于 CBR 编码。但请注意,在其他条件相同的情况下,2-pass 速率控制模式的性能低于 1-pass 速率控制模式。客户端应用程序应在评估各种模式后选择合适的多通道速率控制模式,因为每种模式都有其自身的优点和缺点。NV_ENC_TWO_PASS_FULL_RESOLUION
为第二遍生成更好的统计数据,而导致NV_ENC_TWO_PASS_QUARTER_RESOLUTION
更大的运动向量被捕获并作为第二遍的提示馈送。
设置编码会话属性
一旦所有编码器设置完成,客户端应该填充一个NV_ENC_CONFIG
结构并将其用作输入来NvEncInitializeEncoder
冻结当前编码会话的编码设置。某些设置(例如速率控制模式、平均比特率、分辨率等)可以即时更改。
操作模式
如果客户端要NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync
以异步模式操作,则应设置为 1;如果要以同步模式操作,则应设置为 0。
仅 Windows 10 及更高版本支持异步模式编码。更详细的解释请参见第 6 章。
图片式决策
如果客户端想要按显示顺序发送输入缓冲区,则必须设置enablePTD = 1.
如果enablePTD
设置为 1,则由 NVENCODE API 决定确定图片类型。
如果客户端想要按编码顺序发送输入缓冲区,则必须设置enablePTD = 0,
并指定
NV_ENC_PIC_PARAMS::pictureType
NV_ENC_PIC_PARAMS_H264/NV_ENC_PIC_PARAMS_HEVC/NV_ENC_PIC_PARAMS_AV1::displayPOCSyntax
NV_ENC_PIC_PARAMS_H264/NV_ENC_PIC_PARAMS_HEVC/NV_ENC_PIC_PARAMS_AV1::refPicFlag
NV_ENC_PIC_PARAMS_AV1::goldenFrameFlag/arfFrameFlag/arf2FrameFlag/bwdFrameFlag/overlayFrameFlag
创建保存输入/输出数据所需的资源
一旦编码会话初始化,客户端应该分配缓冲区来保存输入/输出数据。
客户端可以通过调用API选择通过NVIDIA视频编码器接口分配输入缓冲区NvEncCreateInputBuffer
。在这种情况下,客户端负责在关闭编码会话之前销毁分配的输入缓冲区。客户端还有责任根据所选的输入缓冲区格式用有效的输入数据填充输入缓冲区。
客户端应使用 API 分配缓冲区来保存输出编码比特流NvEncCreateBitstreamBuffer
。客户端有责任在关闭编码会话之前销毁这些缓冲区。
或者,在客户端无法或不想通过 NVIDIA 视频编码器接口分配输入缓冲区的情况下,它可以使用任何外部分配的 DirectX 资源作为输入缓冲区。然而,客户端在使用前必须执行一些简单的处理,将这些资源映射到 NVIDIA 视频编码器接口可识别的资源句柄。转换过程在外部分配的输入缓冲区部分中进行了解释。
如果客户端已使用 CUDA 设备来初始化编码器会话,并且希望使用未通过 NVIDIA 视频编码器接口分配的输入缓冲区,则客户端需要使用通过cuMemAlloc
API 系列分配的缓冲区。NVIDIA 视频编码器接口支持CUdeviceptr
和CUarray
输入格式。
如果客户端已使用 OpenGL 设备类型来初始化编码器会话,并且希望使用未通过 NVIDIA 视频编码器接口分配的输入缓冲区,则客户端需要提供之前分配的纹理。
客户端可以使用 生成纹理glGenTextures()
,将其绑定到NV_ENC_INPUT_RESOURCE_OPENGL_TEX::GL_TEXTURE_RECTANGLE
或NV_ENC_INPUT_RESOURCE_OPENGL_TEX::GL_TEXTURE_2D
目标,使用 为其分配存储空间glTexImage2D()
并将数据复制到其中。
请注意,NVENCODE API 的 OpenGL 接口仅在 Linux 上受支持。
如果客户端使用 DirectX 12 设备来初始化编码器会话,则客户端必须使用ID3D12Device::CreateCommittedResource()
API 分配输入和输出缓冲区。客户端在使用前必须执行一些简单的处理,将这些输入和输出资源映射到 NVIDIA 视频编码器接口可识别的资源句柄。DirectX 12 的输入输出缓冲区分配部分中解释了转换过程。
注意:客户端应至少分配 (1 + N B) 个输入和输出缓冲区,其中N B 是连续 P 帧之间的 B 帧数。
检索序列参数
配置编码会话后,客户端可以随时通过调用检索序列参数信息(H.264/HEVC 的 SPS 和 AV1 的序列头 OBU)NvEncGetSequenceParams
。客户端负责分配并最终取消分配大小的缓冲区MAX_SEQ_HDR_LEN
来保存序列参数信息。
默认情况下,SPS/PPS 和序列头 OBU 数据将分别附加到 H.264/HEVC 和 AV1 的每个 IDR 帧和关键帧。然而,客户端也可以请求编码器按需生成SPS/PPS和序列头OBU数据。为了实现这一点,设置NV_ENC_PIC_PARAMS::encodePicFlags
=NV_ENC_PIC_FLAG_OUTPUT_SPSPPS.
当前输入生成的输出比特流将包括 H.264/HEVC 的 SPS/PPS 或 AV1 的序列头 OBU。
NvEncGetSequenceParams
在编码器初始化 ( ) 并且会话处于活动状态后,客户端可以随时NvEncInitializeEncoder
调用。
配置编码会话并分配输入/输出缓冲区后,客户端就可以开始流式传输输入数据以进行编码。客户端需要将有效输入缓冲区的句柄和有效比特流(输出)缓冲区传递给 NVIDIA 视频编码器接口,以对输入图片进行编码。
准备编码输入缓冲区
通过 NVIDIA 视频编码器接口分配的输入缓冲区
如果客户端已经通过 分配了输入缓冲区NvEncCreateInputBuffer
,则客户端需要先填充有效的输入数据,然后才能使用该缓冲区作为编码的输入。为此,客户端应调用NvEncLockInputBuffer
以获取指向输入缓冲区的 CPU 指针。一旦客户端填写了输入数据,它应该调用NvEncUnlockInputBuffer
. 输入缓冲区只有在解锁后才应传递给编码器。任何输入缓冲区都应在销毁/重新分配它们之前通过调用来解锁NvEncUnlockInputBuffer
。
外部分配的输入缓冲区
要将外部分配的缓冲区传递给编码器,请按照下列步骤操作:
NV_ENC_REGISTER_RESOURCE
使用外部分配的缓冲区的属性进行填充。- 使用上面步骤中填充的
NvEncRegisterResource
内容进行调用。NV_ENC_REGISTER_RESOURCE
NvEncRegisterResource
返回一个NV_ENC_REGISTER_RESOURCE::registeredResource
应保存在其中的不透明句柄。NvEncMapInputResource
使用上面返回的句柄进行调用。- 映射的句柄将在以下位置可用
NV_ENC_MAP_INPUT_RESOURCE::mappedResource.
- 客户端应该使用这个映射的handle(
NV_ENC_MAP_INPUT_RESOURCE::mappedResource
)作为输入缓冲区句柄NV_ENC_PIC_PARAMS
。 - 客户端使用完资源后
NvEncUnmapInputResource
必须调用。 - 在销毁注册的资源之前,客户端还必须
NvEncUnregisterResource
使用返回的句柄进行调用。NvEncRegisterResource
当映射资源句柄 ( NV_ENC_MAP_INPUT_RESOURCE::mappedResource
) 处于映射状态时,不得将其用于 NVIDIA 视频编码器接口之外的任何其他目的。不支持这种用法,并且可能会导致未定义的行为。
DirectX 12 的输入输出缓冲区分配
输入和输出缓冲区的分配应按以下方式完成:
- 输入缓冲区应使用 DirectX 12
ID3D12Device::CreateCommittedResource()
API 通过指定D3D12_HEAP_PROPERTIES::Type = D3D12_HEAP_TYPE_DEFAULT
和 来创建D3D12_RESOURCE_DESC::Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D
。 - 应使用 DirectX 12
ID3D12Device::CreateCommittedResource()
API 通过指定D3D12_HEAP_PROPERTIES::Type = D3D12_HEAP_TYPE_READBACK
和创建输出缓冲区D3D12_RESOURCE_DESC::Dimension = D3D12_RESOURCE_DIMENSION_BUFFER
。 - 对于 HEVC、H.264 或 AV1 编码,建议的输出缓冲区大小为:
Output buffer size = 2 * Input YUV buffer size
以字节为单位。
要将这些外部分配的输入和输出缓冲区传递给编码器,请执行以下步骤:
NV_ENC_REGISTER_RESOURCE
使用外部分配的缓冲区的属性进行填充。- 为了在 DirectX 12 中启用显式同步,API
NvEncRegisterResource
接受两个NV_ENC_FENCE_POINT_D3D12
指针类型对象(栅栏点是一对ID3D12Fence
指针和value
),NV_ENC_REGISTER_RESOURCE_PARAMS_D3D12::pInputFencePoint
以及NV_ENC_REGISTER_RESOURCE_PARAMS_D3D12::pOutputFencePoint
,用于注册输入缓冲区。NVENC 引擎会等到pInputFencePoint
到达后才处理NV_ENC_REGISTER_RESOURCE::resourceToRegister
. NVENC 引擎在pOutputFencePoint
资源处理完成时发出信号,以便需要使用该资源的其他引擎可以开始处理。 - 使用上面步骤中填充的
NvEncRegisterResource
内容进行调用。NV_ENC_REGISTER_RESOURCE
NvEncRegisterResource
返回一个NV_ENC_REGISTER_RESOURCE::registeredResource
应保存在其中的不透明句柄。- 客户端应该使用这个注册的句柄( )分别作为和
NV_ENC_REGISTER_RESOURCE::registeredResource
中的输入和输出缓冲区句柄。NV_ENC_INPUT_RESOURCE_D3D12::pInputBuffer
NV_ENC_INPUT_RESOURCE_D3D12::pOutputBuffer
- 在销毁注册的资源之前,客户端还必须
NvEncUnregisterResource
使用返回的句柄进行调用。NvEncRegisterResource
当注册资源句柄 ( NV_ENC_REGISTER_RESOURCE::registeredResource
) 处于注册状态时,不得将其用于 NVIDIA 视频编码器接口之外的任何其他目的。不支持这种用法,并且可能会导致未定义的行为。
配置每帧编码参数
客户端应填充要NV_ENC_PIC_PARAMS
应用于当前输入图片的参数。客户端可以在每帧的基础上执行以下操作。
强制将当前帧编码为帧内帧
要强制当前帧为帧内 (I) 帧,请设置
NV
_ENC_PIC_PARAMS::encodePicFlags = NV_ENC_PIC_FLAG_FORCEINTRA
强制将当前帧用作参考帧
要强制将当前帧用作参考帧,请设置
NV_ENC_PIC_PARAMS_H264/NV_ENC_PIC_PARAMS_HEVC/NV_ENC_PIC_PARAMS_AV1::refPicFlag = 1
强制当前帧用作 IDR 帧
要强制将当前帧编码为 IDR 帧,请设置
NV
_ENC_PIC_PARAMS::encodePicFlags = NV_ENC_PIC_FLAG_FORCEIDR
请求生成序列参数
要包含 SPS/PPS(H.264 和 HEVC)或序列头 OBU (AV1) 以及当前编码的帧,请设置NV_ENC_PIC_PARAMS::encodePicFlags = NV_ENC_PIC_FLAG_OUTPUT_SPSPPS
提交输入帧进行编码
客户端应该调用NvEncEncodePicture
来执行编码。
输入图片数据将从指定的输入缓冲区中取出,编码过程完成后,编码的比特流将在指定的比特流(输出)缓冲区中可用。
与编解码器无关的参数(例如时间戳、持续时间、输入缓冲区指针等)通过该结构传递NV_ENC_PIC_PARAMS
,而编解码器特定的参数通过该结构传递//NV_ENC_PIC_PARAMS_H264
取决于所使用的编解码器。 NV_ENC_PIC_PARAMS_HEVC
NV_ENC_PIC_PARAMS_AV1
客户端在NV_ENC_PIC_PARAMS
使用NV_ENC_PIC_PARAMS::codecPicParams
成员时应指定特定于编解码器的结构。
如果客户端已使用 DirectX 12 设备来初始化编码器会话,则客户端必须将指针传递给NV_ENC_INPUT_RESOURCE_D3D12
包含NV_ENC_PIC_PARAMS:: inputBuffer
注册资源句柄和相应输入的指针NV_ENC_FENCE_POINT_D3D12
,以便 NVENC 在开始编码之前等待。客户端必须将指针传递给包含注册资源句柄和相应输出的NV_ENC_OUTPUT_RESOURCE_D3D12
in 。NVENC 引擎会等待,直到达到 ,然后才开始处理输入缓冲区。NVENC引擎在资源处理完成时发出信号,以便需要使用这些输入和输出资源的其他引擎可以开始处理。 NV_ENC_PIC_PARAMS::outputBuffer
NV_ENC_FENCE_POINT_D3D12
NV_ENC_INPUT_RESOURCE_D3D12::inputFencePoint
NV_ENC_OUTPUT_RESOURCE_D3D12::outputFencePoint
检索编码输出
输入图片的编码过程完成后,客户端需要调用NvEncLockBitstream
以获取指向编码比特流的CPU指针。客户端可以制作编码数据的本地副本或传递CPU指针以进行进一步处理(例如到媒体文件写入器)。
CPU 指针将保持有效,直到客户端调用NvEncUnlockBitstream
。客户端应NvEncUnlockBitstream
在完成处理输出数据后调用。
如果客户端使用 DirectX 12 设备来初始化编码器会话,则客户端必须传递相同的NV_ENC_OUTPUT_RESOURCE_D3D12
指针NV_ENC_LOCK_BITSTREAM::outputBitstream
以检索在编码期间发送的输出NV_ENC_PIC_PARAMS::outputBuffer
。
客户端必须确保所有比特流缓冲区在销毁/取消分配之前(例如,在关闭编码会话时)或者甚至在将它们重新用作后续帧的输出缓冲区之前都已解锁。
通知输入流结束
要通知输入流结束,客户端必须将NvEncEncodePicture
标志NV_ENC_PIC_PARAMS:: encodePicFlags
设置为NV_ENC_FLAGS_EOS
并将所有其他成员NV_ENC_PIC_PARAMS
设置为 0 进行调用。调用 EOS 通知时不需要输入缓冲区NvEncEncodePicture
。
EOS 通知有效地刷新了编码器。这可以在单个编码会话中多次调用。然而,此操作必须在关闭编码会话之前完成。
释放资源
编码完成后,客户端应销毁所有分配的资源。
如果客户端NvEncDestroyInputBuffer
已通过 NVIDIA 视频编码器接口分配了输入缓冲区,则应进行调用。客户端必须确保在销毁输入缓冲区之前首先通过调用将其解锁NvEncUnlockInputBuffer
。
客户端应该调用NvEncDestroyBitstreamBuffer
来销毁它分配的每个比特流缓冲区。客户端必须确保在销毁比特流缓冲区之前首先通过调用将其解锁NvEncUnlockBitstream
。
关闭编码会话
客户端应调用NvEncDestroyEncoder
以关闭编码会话。客户端应确保在调用之前已销毁与正在关闭的编码会话相关的所有资源NvEncDestroyEncoder
。其中包括输入缓冲区、比特流缓冲区、SPS/PPS 缓冲区等。
它还必须确保所有已注册的事件均已取消注册,并且所有映射的输入缓冲区句柄均已取消映射。
异步模式
该操作模式用于异步输出缓冲区处理。对于此模式,客户端分配一个事件对象并将该事件与分配的输出缓冲区相关联。该事件对象作为NvEncEncodePicture
API 的一部分传递到 NVIDIA 编码器接口。客户端可以在单独的线程中等待该事件。当事件发出信号时,客户端调用 NVIDIA 视频编码器接口来复制编码器生成的输出比特流。请注意,编码器仅支持 Windows 10 及更高版本的异步操作模式,且驱动程序在 WDDM 模式下运行。在具有 TCC 模式的 Linux 和 Windows 中(TCC 模式在 Tesla 板1上可用),仅支持同步模式(请参阅同步模式部分)
客户端应将该标志设置NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync
为 1 以指示它希望以异步模式操作。创建事件对象(分配的每个输出比特流缓冲区一个对象)后,客户端需要使用NvEncRegisterAsyncEvent
. 客户端需要传递比特流缓冲区句柄和相应的事件句柄作为 的输入NvEncEncodePicture
。当硬件编码器完成当前输入数据的编码时,NVIDIA 视频编码器接口将发出此事件信号。然后,客户端可以调用设置为 1 的NvEncLockBitstream
非阻塞模式NV_ENC_LOCK_BITSTREAM::doNotWait
标志来获取输出数据。
客户端应该NvEncUnregisterAsyncEvent
在销毁事件对象之前调用取消注册事件句柄。只要有可能,NVIDIA 建议使用异步操作模式而不是同步模式。
异步模式的分步控制流程如下:
- 在异步模式下工作时,输出样本必须由事件 + 输出缓冲区组成,并且客户端必须以多线程方式工作(D3D9 设备应使用 MULTITHREADED 标志创建)。
- 输出缓冲区使用
NvEncCreateBitstreamBuffer
API 进行分配。NVIDIA 视频编码器接口将返回一个指向输出内存的不透明指针NV_ENC_CREATE_BITSTREAM_BUFFER::bitstreambuffer
。NvEncEncodePicture
这个不透明的输出指针应该在andNvEncLockBitsteam
/调用中使用NvEncUnlockBitsteam
。要使用 CPU 访问输出内存,客户端必须调用NvEncLockBitsteam
API。IO 缓冲区的数量应至少为 4 + B 帧的数量。 - 这些事件是使用 Windows
CreateEvent
API 分配的 Windows 事件句柄,并在编码之前使用函数注册NvEncRegisterAsyncEvent
。每个编码会话仅需要注册一次事件。NvEncUnregisterAsyncEvent
在销毁事件句柄之前,客户端必须取消注册事件。事件句柄的数量必须与输出缓冲区的数量相同,因为每个输出缓冲区都与一个事件关联。 - 客户端必须创建一个辅助线程,在其中可以等待完成事件并从输出样本复制比特流数据。客户端将有两个线程:一个是主应用程序线程,它将编码工作提交给 NVIDIA Encoder,而辅助线程则等待完成事件并从输出缓冲区复制压缩的比特流数据。
NV_ENC_PIC_PARAMS::outputBitstream
客户端必须分别在和字段中发送输出缓冲区和事件,NV_ENC_PIC_PARAMS:: completionEvent
作为NvEncEncodePicture
API 调用的一部分。- 然后,客户端应按照调用顺序相同的顺序在辅助线程上等待事件,而
NvEncEncodePicture
不管输入缓冲区重新排序(编码顺序!=显示顺序)。当 时enablePTD = 1
,NVIDIA Encoder 会以对编码器客户端透明的方式处理 B 帧的重新排序。对于 AV1,NVIDIA 编码器还透明地执行帧比特流打包,这意味着它始终将与前导未显示帧相对应的比特流与随后的第一个显示帧的比特流连接到单个输出缓冲区中。因此,每个输出缓冲区始终包含要显示的单个帧以及自上一个要显示的帧以来按编码顺序的所有前面的非显示帧。 - 当事件收到信号时,客户端必须发送样本事件的输出缓冲区,它作为调用的
NV_ENC_LOCK_BITSTREAM::outputBitstream
一部分在现场等待NvEncLockBitstream
。 - NVIDIA 编码器接口返回 CPU 指针和比特流大小(以字节为单位)作为
NV_ENC_LOCK_BITSTREAM
. - 复制比特流数据后,客户端必须调用
NvEncUnlockBitstream
锁定的输出比特流缓冲区。
笔记:
- 客户端将按照事件的排队顺序接收事件的信号和输出缓冲区。
- 通知
NV_ENC_LOCK_BITSTREAM::pictureType
客户端输出图片类型。 - 一旦 NVIDIA 视频编码器接口发出事件信号并且客户端已从输出缓冲区复制数据,输入和输出样本(输出缓冲区和输出完成事件)都可以自由重用。
同步模式
该操作模式用于同步输出缓冲区处理。在此模式下,客户端对 NVIDIA 视频编码器接口进行阻塞调用,以从编码器检索输出比特流数据。客户端将标志设置NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync
为 0 以同步模式操作。然后,客户端必须NvEncEncodePicture
在不设置完成事件句柄的情况下进行调用。客户端必须将NvEncLockBitstream
标志NV_ENC_LOCK_BITSTREAM::doNotWait
设置为 0 进行调用,以便锁定调用会阻塞,直到硬件编码器完成写入输出比特流。然后,客户端可以对生成的比特流数据进行操作并调用NvEncUnlockBitstream
. 这是 Linux 上唯一支持的模式。
线程模型
为了获得最大的编码性能,编码器客户端应创建一个单独的线程来等待事件或对编码器接口进行任何阻塞调用。
客户端应避免从主编码器处理线程进行任何阻塞调用。主编码器线程应仅用于编码器初始化以及使用NvEncEncodePicture
API(非阻塞)向硬件编码器提交工作。
输出缓冲区处理,例如在异步模式下等待完成事件或在同步模式下调用NvEncLockBitstream
/等阻塞 API NvEncUnlockBitstream
,应在辅助线程中完成。这确保了主编码器线程永远不会被阻塞,除非编码器客户端耗尽资源。
还建议分配许多输入和输出缓冲区,以避免资源危险并提高编码器的整体吞吐量。
IDXGIOutputDuplication::AcquireNextFrame
在 Windows 上,当编码设备类型为 DirectX 时,从主线程和NvEncLockBitstream
/或辅助线程调用 DXGI APINvEncUnlockBitstream
可能会导致次优或未定义的行为。这是因为NvEncLockBitstream
可以在内部使用应用程序的 DirectX 设备。
为了在此类应用中获得最佳性能,应使用以下编码器设置:
NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync = 1
NV_ENC_LOCK_BITSTREAM::doNotWait = 0
NV_ENC_INITIALIZE_PARAMS::enableOutputInVidmem = 0
使用 CUDA 的编码器功能
虽然 GPU 上的核心视频编码器硬件完全独立于 GPU 上的 CUDA 内核或图形引擎,但以下编码器功能在内部使用 CUDA 进行硬件加速。
启用这些功能对整体 CUDA 或图形性能的影响很小,此列表仅供参考。
- 高质量预设的两次通过率控制模式
- 展望
- 所有自适应量化模式
- 加权预测
- RGB内容的编码
NVENC可用作硬件加速器来执行运动搜索并生成运动矢量和模式信息。所得到的运动矢量或模式决策可用于例如运动补偿滤波或用于支持 NVENC 不完全支持的其他编解码器或简单地用作自定义编码器的运动矢量提示。下面解释了使用该功能的过程。
对于涉及计算机视觉、人工智能和帧插值的用例,Turing 和后来的 GPU 包含另一个硬件加速器,用于计算帧之间的光流向量,它提供比运动向量更好的视觉匹配。
查询仅运动估计模式功能
在使用仅运动估计 (ME) 模式之前,客户端应显式查询编码器支持仅 ME 模式的能力。为此,客户应执行以下操作:
NV_ENC_CAPS_SUPPORT_MEONLY_MODE
通过参数指定要查询的能力属性NV_ENC_CAPS_PARAM::capsToQuery
。- 客户端应调用
NvEncGetEncoderCaps
以确定对所需属性的支持。
NV_ENC_CAPS_SUPPORT_MEONLY_MODE 指示硬件中仅支持 ME 模式。
0:不支持仅 ME 模式。
1:仅支持 ME 模式。
如果使用 DirectX 12 设备,则不支持仅运动估计 (ME) 模式。
为输入/输出数据创建资源
客户端应通过调用API为输入图片分配至少1个缓冲区NvEncCreateInputBuffer
,并且还应通过NvEncCreateInputBuffer
API为参考帧分配1个缓冲区。客户端负责填写有效的输入数据。
输入资源创建完成后,客户端需要通过API为输出数据分配资源NvEncCreateMVBuffer
。
填充仅 ME 模式设置
该结构NV_ENC_CODEC_CONFIG::NV_ENC_CONFIG_H264_MEONLY
提供了控制 NVENC 硬件返回的运动矢量和模式的分区类型的能力。具体来说,客户端可以通过设置以下标志来禁用帧内模式和/或特定 MV 分区大小:
NV_ENC_CONFIG_H264_MEONLY::disableIntraSearch
NV_ENC_CONFIG_H264_MEONLY::disablePartition16x16 NV_ENC_CONFIG_H264_MEONLY::disablePartition8x16 NV_ENC_CONFIG_H264_MEONLY::disablePartition16x8 NV_ENC_CONFIG_H264_MEONLY::disablePartition8x8
API 还公开了一个参数NV_ENC_CONFIG::NV_ENC_MV_PRECISION
来控制硬件返回的运动矢量的精度。对于全像素精度,客户端必须忽略运动矢量的两个 LSB。对于亚像素精度,运动矢量的两个 LSB 表示运动矢量的小数部分。为了获得每个宏块的运动向量,建议通过设置禁用帧内模式NV_ENC_CONFIG_H264_MEONLY::disableIntraSearch = 1
,并让 NVENC 决定运动向量的最佳分区大小。
跑步运动估计
客户端应该创建一个 的实例NV_ENC_MEONLY_PARAMS
。
输入图片缓冲区和参考帧缓冲区的指针需要分别输入NV_ENC_MEONLY_PARAMS::inputBuffer
和NV_ENC_MEONLY_PARAMS::referenceFrame
。
NvEncCreateMVBuffer
需要将字段中 API返回的指针NV_ENC_CREATE_MV_BUFFER::mvBuffer
提供给NV_ENC_MEONLY_PARAMS::mvBuffer
.
为了以异步模式操作,客户端应该创建一个事件并将该事件传递到NV_ENC_MEONLY_PARAMS::completionEvent
. 该事件将在运动估计完成时发出信号。每个输出缓冲区应与一个不同的事件指针相关联。
客户端应调用NvEncRunMotionEstimationOnly
在硬件编码器上运行运动估计。
对于异步模式,客户端应在重用输出缓冲区和应用程序终止之前等待运动估计完成信号。
客户端必须锁定NV_ENC_CREATE_MV_BUFFER::mvBuffer
使用NvEncLockBitstream
才能获取运动矢量数据。
最后,NV_ENC_LOCK_BITSTREAM::bitstreamBufferPtr
其中包含的输出运动向量应NV_ENC_H264_MV_DATA*/NV_ENC_HEVC_MV_DATA*
分别针对 H.264/HEVC 进行类型转换。NV_ENC_CREATE_MV_BUFFER::mvBuffer
然后,客户端应通过调用 来解锁NvEncUnlockBitstream
。
为立体用例启用运动估计
对于需要处理两个视图的立体用例,我们建议采用以下方法来提高运动矢量的性能和质量:
- 客户端应创建单个编码会话。
- 客户端应该在不同的线程上开始处理左视图和右视图。
- 客户端应将
NV_ENC_MEONLY_PARAMS::viewID
左视图和右视图设置为 0 和 1。 - 主线程应等待已为左视图和右视图启动 NVENC 的线程完成。
释放创建的资源
一旦完成运动估计的使用,客户端应调用NvEncDestroyInputBuffer
以销毁输入图片缓冲区和参考帧缓冲区,并应调用NvEncDestroyMVBuffer
以销毁运动矢量数据缓冲区。
展望
前瞻技术使编码器能够缓冲指定数量的帧、估计其复杂性并根据其复杂性按比例在这些帧之间适当地分配比特,从而提高视频编码器的速率控制精度。这也动态分配 B 和 P 帧。
要使用此功能,客户端必须执行以下步骤:
- 可以使用以下命令查询当前硬件中该功能的可用性
NvEncGetEncodeCaps
并检查NV_ENC_CAPS_SUPPORT_LOOKAHEAD.
- 需要在初始化期间通过设置 = 1 来启用前瞻
NV_ENC_INITIALIZE_PARAMS::encodeconfig->rcParams.enableLookahead
。 - 应设置要向前查看的帧数,
NV_ENC_INITIALIZE_PARAMS::encodeconfig->rcParams.lookaheadDepth
最多可达 32 帧。 - 默认情况下,前瞻功能启用帧内帧和 B 帧的自适应插入。
NV_ENC_INITIALIZE_PARAMS::encodeconfig->rcParams.disableIadapt
不过,可以通过将和/或设置为 1来禁用它们NV_ENC_INITIALIZE_PARAMS::encodeconfig->rcParams.disableBadapt
。 - 启用该功能后,帧会在编码器中排队,因此
NvEncEncodePicture
会返回NV_ENC_ERR_NEED_MORE_INPUT
,直到编码器有足够数量的输入帧来满足前瞻要求。应连续送入框架直至NvEncEncodePicture
返回NV_ENC_SUCCESS
。
B 帧作为参考
使用 B 帧作为参考可提高主观和客观编码质量,且不会影响性能。因此强烈建议启用多个B帧的用户启用此功能。
要使用该功能,请按照下列步骤操作:
- 使用 API 查询该功能的可用性
NvEncGetEncodeCaps
并检查NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE
返回值。 - 在编码器初始化期间,设置
NV_ENC_CONFIG_H264/NV_ENC_CONFIG_HEVC/NV_ENC_CONFIG_AV1::useBFramesAsRef
=NV_ENC_BFRAME_REF_MODE_MIDDLE
:- 对于 H.264 和 HEVC,这会将第 (N/2) 个 B 帧设置为参考,其中 N = B 帧的数量。如果 N 为奇数,则将选取第 (N-1)/2 帧作为参考。
- 对于 AV1,这会将每隔一个 B 帧设置为 Altref2 参考,但对于 Altref 间隔中的最后一个 B 帧。
重新配置API
NvEncReconfigureEncoder
允许客户端更改编码器初始化参数,而NV_ENC_INITIALIZE_PARAMS
无需关闭现有编码器会话并重新创建新的编码会话。这有助于客户端避免由于编码会话的破坏和重新创建而引入的延迟。该API适用于视频会议、游戏串流等传输介质容易不稳定的场景。
使用此 API 客户端可以使用相同的编码会话动态更改比特率、帧率、分辨率等参数。重新配置的参数通过NV_ENC_RECONFIGURE_PARAMS::reInitEncodeParams.
不过,该API目前不支持所有参数的重新配置,下面列出了其中一些参数:
- 改变共和党结构 (
NV_ENC_CONFIG_H264::idrPeriod,
NV_ENC_CONFIG::gopLength, NV_ENC_CONFIG::frameIntervalP
) - 从同步编码模式更改为异步模式,反之亦然。
- 改变
NV_ENC_INITIALIZE_PARAMS::maxEncodeWidth
和NV_ENC_INITIALIZE_PARAMS::maxEncodeHeight.
- 更改 中的图片类型决定
NV_ENC_INITIALIZE_PARAMS::enablePTD
。 - 更改位深度。
- 更改色度格式。
- 改变
NV_ENC_CONFIG_HEVC::maxCUSize
。 - 改变
NV_ENC_CONFIG::frameFieldMode
。
如果尝试重新配置不支持的参数,API 将失败。
仅当创建编码器会话时设置 NV_ENC_INITIALIZE_PARAMS::maxEncodeWidth
和时,才可以更改分辨率。NV_ENC_INITIALIZE_PARAMS::maxEncodeHeight
如果客户端希望使用此 API 更改分辨率,建议通过设置为NV_ENC_RECONFIGURE_PARAMS::forceIDR
1 来强制重新配置后的下一帧为 IDR 帧。
如果客户端希望重置内部速率控制状态,请设置NV_ENC_RECONFIGURE_PARAMS::resetEncoder to
1。
自适应量化 (AQ)
此功能通过根据序列的空间和时间特征调整编码 QP(在速率控制算法评估的 QP 之上)来提高视觉质量。目前的SDK支持两种类型的AQ,解释如下:
空间AQ
空间 AQ 模式根据帧的空间特性调整 QP 值。由于低复杂度平坦区域在视觉上比高复杂度细节区域更容易感知质量差异,因此以具有高空间细节的区域为代价将额外的比特分配给帧的平坦区域。尽管空间 AQ 提高了编码视频的可感知视觉质量,但在大多数情况下,所需的比特重新分配会导致 PSNR 下降。因此,在基于 PSNR 的评估过程中,应关闭该功能。
要使用空间 AQ,请在您的应用程序中执行以下步骤。
- 可以通过设置在初始化期间启用空间 AQ
NV_ENC_INITIALIZE_PARAMS::encodeconfig->rcParams. enableAQ = 1
。 - QP 调整的强度可以通过设置来控制
NV_ENC_INITIALIZE_PARAMS::encodeconfig->rcParams.aqStrength
,范围从 1(最不积极)到 15(最积极)。如果未设置,强度由驱动程序自动选择。
时间AQ
时间 AQ 尝试根据序列的时间特性调整编码 QP(在速率控制算法评估的 QP 之上)。时间 AQ 通过调整帧间恒定或低运动但具有高空间细节的区域的 QP 来提高编码帧的质量,从而使它们成为未来帧的更好参考。将额外的比特分配给参考帧中的此类区域比将它们分配给参考帧中的残差更好,因为这有助于提高整体编码视频质量。如果帧内的大部分区域几乎没有运动或没有运动,但具有高空间细节(例如高细节的非运动背景),则启用时间 AQ 将受益最多。
时间 AQ 的潜在缺点之一是启用时间 AQ 可能会导致 GOP 内每帧消耗的比特波动较大。I/P 帧将比平均 P 帧大小消耗更多的比特,而 B 帧将消耗更少的比特。尽管目标比特率将保持在 GOP 级别,但与没有临时 AQ 的情况相比,GOP 内帧大小从一帧到下一帧的波动更大。如果 GOP 内的每个帧大小都需要严格的 CBR 配置文件,则不建议启用临时 AQ。此外,由于一些复杂性估计是在 CUDA 中执行的,因此启用临时 AQ 时可能会对性能产生一些影响。
要使用临时 AQ,请在您的应用程序中执行以下步骤。
- 通过调用 API NvEncGetEncodeCaps 并检查 NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ,查询当前硬件的临时 AQ 的可用性。
- 如果支持,可以通过设置 NV_ENC_INITIALIZE_PARAMS::encodeconfig->rcParams.enableTemporalAQ = 1 在初始化期间启用临时 AQ。
Temporal AQ 使用 CUDA 预处理,因此需要 CUDA 处理能力,具体取决于分辨率和内容。
启用时间 AQ 可能会导致编码器性能出现非常轻微的下降。
高位深度编码
所有 NVIDIA GPU 都支持 8 位编码(8 位精度的 RGB/YUV 输入)。从 Pascal 一代开始,NVIDIA GPU 支持高位深度 HEVC 编码(具有 10 位输入精度的 HEVC main-10 配置文件)。从 Ada 一代开始,NVIDIA GPU 支持高位深度 AV1 编码(具有 8 或 10 位输入精度的 AV1 主配置文件)。要对 10 位内容进行编码,请遵循以下步骤。
NvEncGetEncodeCaps
可以使用并检查 来查询该功能的可用性NV_ENC_CAPS_SUPPORT_10BIT_ENCODE
。NV_ENC_HEVC_PROFILE_MAIN10_GUID
为 HEVC 或AV1创建编码器会话NV_ENC_AV1_PROFILE_MAIN_GUID
。- 在编码器初始化期间,
- 对于 HEVC,设置
encodeConfig->encodeCodecConfig.hevcConfig.pixelBitDepthMinus8 = 2
. - 对于 AV1,设置
encodeConfig->encodeCodecConfig.av1Config.pixelBitDepthMinus8 = 2
和encodeConfig->encodeCodecConfig.av1Config.inputPixelBitDepthMinus8 = 0
为 8 位输入内容或encodeConfig->encodeCodecConfig.av1Config.inputPixelBitDepthMinus8 = 2
10 位输入内容。对于 8 位输入内容,NVENC 在编码之前对输入执行内部 8 到 10 位转换。
- 对于 HEVC,设置
- 对于 HEVC,输入表面格式需要设置为
NV_ENC_BUFFER_FORMAT_YUV420_10BIT
ORNV_ENC_BUFFER_FORMAT_ABGR10
或NV_ENC_BUFFER_FORMAT_ARGB10
或NV_ENC_BUFFER_FORMAT_YUV444_10BIT
,具体取决于输入的性质。对于 AV1,输入表面格式可以是任何支持的格式。 - 其他编码参数如预设、码率控制模式等可根据需要设置。
加权预测
加权预测涉及乘法加权因子和运动补偿预测的加性偏移的计算。加权预测为具有照明变化的内容提供了显着的质量增益。NVENCODE API 支持从 Pascal 代 GPU 开始对 HEVC 和 H.264 进行加权预测。
需要遵循以下步骤来启用加权预测。
NvEncGetEncodeCaps
可以使用并检查 来查询该功能的可用性NV_ENC_CAPS_SUPPORT_WEIGHTED_PREDICTION
。- 在编码器初始化期间,设置
NV_ENC_INITIALIZE_PARAMS:: enableWeightedPrediction = 1
.
如果编码会话配置有 B 帧,则不支持加权预测。
如果使用 DirectX 12 设备,则不支持加权预测。
加权预测使用 CUDA 预处理,因此需要 CUDA 处理能力,具体取决于分辨率和内容。
启用加权预测还可能导致编码器性能非常轻微的下降。
H.264 和 HEVC 的长期参考
NVENCODE API 提供了将特定帧标记和使用为长期参考 (LTR) 帧的功能,稍后可以将其用作对当前图片进行编码的参考。这有助于隐藏错误,客户端解码器可以根据长期参考帧进行预测,以防中间帧丢失数据。该功能在视频流应用中非常有用,可以从接收器的帧丢失中恢复。
要启用该功能,请执行以下步骤。
- 在编码器初始化期间,
- 对于 H.264,设置
NV_ENC_CONFIG_H264:enableLTR
= 1 - 对于 HEVC,设置
NV_ENC_CONFIG_HEVC:enableLTR
= 1
- 对于 H.264,设置
NvEncGetEncoderCaps
可以使用和 检查 来查询当前硬件支持的长期参考图片的最大数量NV_ENC_CAPS_NUM_MAX_LTR_FRAMES
。
在正常编码操作期间,需要遵循以下步骤将特定帧标记为LTR帧。
- 配置LTR帧数:
- 对于 H.264,设置
NV_ENC_CONFIG_H264:ltrNumFrames
- 对于 HEVC,设置
NV_ENC_CONFIG_HEVC:ltrNumFrames
- 对于 H.264,设置
- 客户端可以通过分别为 H.264 和 HEVC 设置
NV_ENC_PIC_PARAMS_H264::ltrMarkFrame = 1
OR将任何帧标记为 LTRNV_ENC_PIC_PARAMS_HEVC::ltrMarkFrame = 1
。每个LTR帧需要被分配一个LTR帧索引。该值应介于 0 和 之间ltrNumFrames
- 1
。 - 可以通过分别为 H264 和 HEVC设置
NV_ENC_PIC_PARAMS_H264::ltrMarkFrameIdx
OR来分配 LTR 帧索引。NV_ENC_PIC_PARAMS_HEVC::ltrMarkFrameIdx
先前标记为长期参考帧的帧可以通过以下方式用于当前帧的预测:
- 必须分别使用H.264 和 HEVC 的
NV_ENC_PIC_PARAMS_H264::ltrUseFrameBitmap
OR来指定要用作参考的 LTR 帧NV_ENC_PIC_PARAMS_HEVC::ltrUseFrameBitmap
。位位置指定将用作参考的帧的 LTR 帧索引。
当编码会话配置为B帧时,当前SDK不支持LTR。
重点地图
NVENCODE API 中的强调图功能提供了一种指定帧中要以不同质量级别、宏块级粒度进行编码的区域的方法。根据每个宏块的实际强调级别,编码器对用于编码该宏块的量化参数进行调整。此调整的值取决于以下因素:
- 由速率控制算法决定的 QP 绝对值,取决于速率控制约束。一般来说,对于给定的强调级别,由速率控制确定的QP越高,(负)调整越高。
- 宏块的强调级别值。
QP 调整是在速率控制算法运行后执行的。因此,使用此功能时可能会出现 VBV/速率违规。
当客户端事先了解图像复杂性(例如 NVFBC 的分类图功能)并且以更高质量(较低 QP)对这些高复杂性区域进行编码很重要时,即使可能会违反比特率/VBV 缓冲区,强调级别图很有用尺寸限制。启用 AQ(空间/时间)时不支持此功能。
请按照以下步骤启用该功能。
- 使用 API 查询功能的可用性
NvEncGetEncodeCaps
并检查NV_ENC_CAPS_SUPPORT_EMPHASIS_LEVEL_MAP.
- 放
NV_ENC_RC_PARAMS::qpMapMode = NV_ENC_QP_MAP_EMPHASIS.
- 用以下值填充 这
NV_ENC_PIC_PARAMS::qpDeltaMap (
是一个有符号字节数组,其中包含当前图片的光栅扫描顺序中每个宏块的值)enum NV_ENC_EMPHASIS_MAP_LEVEL.
如上所述,较高的值NV_ENC_EMPHASIS_MAP_LEVEL
意味着对 QP 进行较高(负)调整以强调该宏块的质量。用户可以为他想要以更高质量编码的区域选择更高的强调级别。
视频内存中的 NVENC 输出
从 SDK 9.0 开始,NVENCODE API 支持视频内存中的比特流和 H.264 ME-only 模式输出。这对于使用 CUDA 或 DirectX 着色器执行 NVENC 输出操作的用例很有帮助。将 NVENC 的输出保留在视频内存中可以避免不必要的 PCIe 缓冲区传输。视频内存应由客户端应用程序分配,作为一维缓冲区。目前,H.264、HEVC 和 AV1 编码以及仅 H.264 ME 模式支持此功能。DirectX 11 和 CUDA 接口支持该功能。
请按照以下步骤操作,以便输出在视频内存中可用。
NV_ENC_INITIALIZE_PARAMS::enableOutputInVidmem = 1
调用时设置nvEncInitializeEncoder()
。- 在视频内存中分配一维缓冲区供NVENC写入输出。
- 对于 AV1、HEVC 或 H.264 编码,该缓冲区的建议大小为:
Output buffer size = 2 * Input YUV buffer size + sizeof(NV_ENC_ENCODE_OUT_PARAMS)
首先
sizeof
(NV_ENC_ENCODE_OUT_PARAMS)
输出缓冲区的字节包含NV_ENC_ENCODE_OUT_PARAMS
结构,后面是编码的比特流数据。 - 对于仅 H.264 ME 输出,建议的输出缓冲区大小为:
Output buffer size = HeightInMbs * WidthInMbs * sizeof(NV_ENC_H264_MV_DATA)
其中
HeightInMbs
和WidthInMbs
分别是图像高度和宽度(以 16x16 宏块数表示)。 CreateBuffer()
对于 DirectX 11 接口,可以使用 DirectX 11 API 通过指定usage
=创建此缓冲区D3D11_USAGE_DEFAULT
;BindFlags
= (D3D11_BIND_VIDEO_ENCODER | D3D11_BIND_SHADER_RESOURCE
); 和CPUAccessFlags = 0
;- 对于 CUDA 接口,可以使用以下命令创建该缓冲区
cuMemAlloc().
- 对于 AV1、HEVC 或 H.264 编码,该缓冲区的建议大小为:
- 使用 注册此缓冲区
nvEncRegisterResource()
,方法是指定:NV_ENC_REGISTER_RESOURCE::bufferUsage =
NV_ENC_OUTPUT_BITSTREAM
如果输出是编码比特流,- 就好像
NV_ENC_REGISTER_RESOURCE::bufferUsage= NV_ENC_OUTPUT_MOTION_VECTOR
在仅 H.264 ME 模式的情况下输出是运动矢量。 - 放
NV_ENC_REGISTER_RESOURCE::bufferFormat= NV_ENC_BUFFER_FORMAT_U8
。NvEncRegisterResource()
将返回一个已注册的句柄NV_ENC_REGISTER_RESOURCE::registeredResource
。
NV_ENC_MAP_INPUT_RESOURCE::registeredResource = NV_ENC_REGISTER_RESOURCE::registeredResource
上一步中获得的集合。- 调用
nvEncMapInputResource()
,这将返回 中的映射资源句柄NV_ENC_MAP_INPUT_RESOURCE::mappedResource
。 - 对于AV1/HEVC/H.264编码模式,
nvEncEncodePicture()
通过设置为NV_ENC_PIC_PARAMS::outputBitstream
来调用NV_ENC_MAP_INPUT_RESOURCE:: mappedResource
。 NV_ENC_MEONLY_PARAMS::mvBuffer
对于 H.264 ME-only 模式,通过设置为来调用 nvEncRunMotionEstimationOnly()NV_ENC_MAP_INPUT_RESOURCE::mappedResource
。
读取输出缓冲区时,请注意以下事项:
调用nvEncEncodePicture()
or后nvEncRunMotionEstimationOnly()
,客户端只有在取消映射该输出缓冲区后才能使用该输出缓冲区进行进一步处理。NvEncLockBitstream()
不应该被调用。
在异步模式下操作时,客户端应用程序应在读取输出之前等待事件。在同步模式下,不会触发任何事件,并且同步由 NVIDIA 驱动程序在内部处理。
要访问输出,请按照下列步骤操作:
- 客户端必须通过调用返回的
nvEncUnmapInputResource()
映射资源句柄来取消映射输入缓冲区。此后,输出缓冲区可用于进一步处理/读取等。NV_ENC_MAP_INPUT_RESOURCE::mappedResource
nvEncMapInputResource()
- 在编码的情况下,
sizeof(NV_ENC_ENCODE_OUT_PARAMS)
该缓冲区的第一个字节应解释为NV_ENC_ENCODE_OUT_PARAMS
结构,后跟编码比特流数据。编码比特流的大小由 给出NV_ENC_ENCODE_OUT_PARAMS::bitstreamSizeInBytes
。 - 如果指定了 CUDA 模式,则该缓冲区上的所有 CUDA 操作都必须使用默认流。要获取系统内存中的输出,可以通过
cuMemcpyDtoH()
使用默认流调用任何 CUDA API(例如 )来读取输出缓冲区。驱动程序确保仅在 NVENC 完成将输出写入其中后才能读取输出缓冲区。 - 对于 DX11 模式,任何 DirectX 11 API 都可用于读取输出。驱动程序确保仅在 NVENC 完成将输出写入其中后才能读取输出缓冲区。要获取系统内存中的输出
CopyResource()
(DirectX 11 API),可用于将数据复制到 CPU 可读暂存缓冲区中。Map()
然后可以在调用DirectX 11 API后读取该暂存缓冲区。
HEVC 中的 Alpha 层编码支持
NVENCODE API 实现了对 HEVC 中 alpha 层编码的支持。该功能允许应用程序对包含 YUV 数据的基础层和包含 Alpha 通道数据的辅助层进行编码。
要启用该功能,请执行以下步骤:
nvEncGetEncodeCaps()
可以使用并检查 来查询该功能的可用性NV_ENC_CAPS_SUPPORT_ALPHA_LAYER_ENCODING
。请注意,alpha 层编码仅支持NV_ENC_BUFFER_FORMAT_NV12, NV_ENC_BUFFER_FORMAT_ARGB
和输入格式。NV_ENC_BUFFER_FORMAT_ABGR
- 在编码器初始化期间,设置
NV_ENC_CONFIG_HEVC:: enableAlphaLayerEncoding = 1
. 客户端还可以通过设置指定 YUV 和辅助 alpha 层之间比特率的分配比例NV_ENC_RC_PARAMS::alphaLayerBitrateRatio
。例如,如果NV_ENC_RC_PARAMS::alphaLayerBitrateRatio = 3
75% 的比特将用于基础层编码,而另外 25% 将用于 alpha 层。
在正常编码操作期间,需要遵循以下步骤进行 alpha 层编码:
- 将 alpha 输入传递给
nvEncEncodePicture() :
- 对于输入格式
NV_ENC_BUFFER_FORMAT_NV12
,应传入 YUV 数据NV_ENC_PIC_PARAMS::inputBuffer
,而 alpha 输入数据需要使用 单独传递NV_ENC_PIC_PARAMS::alphaBuffer
。的格式NV_ENC_PIC_PARAMS::alphaBuffer
应该是NV_ENC_BUFFER_FORMAT_NV12
. 亮度平面应包含 alpha 数据,而色度分量应 memset 为 0x80。 - 对于输入格式
NV_ENC_BUFFER_FORMAT_ABGR
或NV_ENC_BUFFER_FORMAT_ARGB
,应传入输入数据NV_ENC_PIC_PARAMS::inputBuffer
。在这种情况下,该字段NV_ENC_PIC_PARAMS::alphaBuffer
应设置为 NULL。
- 对于输入格式
- YUV 的编码输出以及 alpha 层是通过调用 来获取的
NvEncLockBitstream
。该字段NV_ENC_LOCK_BITSTREAM::bitstreamSizeInBytes
将包含总编码大小,即它是 YUV 层比特流数据、alpha 比特流数据和任何其他标头数据的大小。客户可以使用字段单独获取alpha层的大小NV_ENC_LOCK_BITSTREAM::alphaLayerSizeInBytes
。
以下场景不支持 Alpha 编码:
- 当启用更多子帧时。
- 输入图像为 YUV 444。
- 输入图像的位深度为10位。
- 位流输出指定位于视频内存中。
- 启用加权预测。
H.264 中的时间可扩展视频编码 (SVC)
NVENCODE API 支持 H.264/AVC 视频压缩标准附件 G 中指定的时间可伸缩视频编码 (SVC)。时间 SVC 产生具有基础层和多个辅助层的分层结构。
要使用临时 SVC,请执行以下步骤:
- 通过调用 API NvEncGetEncodeCaps 并检查 NV_ENC_CAPS_SUPPORT_TEMPORAL_SVC,查询当前硬件的临时 SVC 的可用性。
- 如果支持,查询 SVC 中支持的最大时间层数,
nvEncGetEncodeCaps()
并检查值NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS
- 在编码器初始化期间,设置
NV_ENC_CONFIG_H264::enableTemporalSVC = 1
.NV_ENC_CONFIG_H264::numTemporalLayers
分别使用和指定时间层数和最大时间层数NV_ENC_CONFIG_H264::maxTemporalLayers
。 - 如果最大时间层数大于 2,则帧重排序的最小 DPB 大小需要为
(maxTemporalLayers - 2) * 2
。因此,请将 设定NV_ENC_CONFIG_H264::maxNumRefFrames
为大于或等于该值。NV_ENC_CONFIG_H264::maxNumRefFrames
请注意,的默认值为NV_ENC_CAPS::NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS
。 - 默认情况下,启用临时 SVC 时会添加 SVC 前缀 NALU。要禁用此功能,请设置
NV_ENC_CONFIG_H264::disableSVCPrefixNalu = 0
. - NVENCODE API 支持在比特流中添加可扩展性信息 SEI 消息。要启用此 SEI,请设置
NV_ENC_CONFIG_H264::enableScalabilityInfoSEI = 1
。该 SEI 将添加到编码比特流中的每个 IDR 帧中。请注意,此 SEI 当前仅支持与时间可伸缩性相关的字段子集。
启用时间 SVC 时,只有基础层帧可以标记为长期参考。
B 帧当前不支持临时 SVC。NV_ENC_CONFIG::frameIntervalP
当启用临时 SVC 时, 该字段将被忽略。
错误恢复功能
在涉及视频流的典型场景中,客户端解码器处经常出现比特错误。为了最大限度地减少这些错误的影响并从此类错误中恢复,NVENCODE API 提供了一些错误恢复功能,本节将对此进行说明。
参考图片失效
NVENCODE API 提供了一种机制,当解码器(客户端)发现客户端解码的图片损坏时,使某些图片失效。这种失效是通过使用 API 来实现的NvEncInvalidateRefFrames
。客户端可以通过要求流媒体服务器上的编码器使该帧无效来防止进一步的损坏,这将阻止所有后续帧使用当前帧作为运动估计的参考帧。然后,服务器基于任何可供参考的内容,使用旧的短期和长期框架作为参考。如果没有帧可供参考,当前帧将被编码为帧内帧。参数NV_ENC_CONFIG_H264::maxNumRefFrames
或确定 DPB 中的帧数,将其设置为较大的值将允许较旧的帧在 DPB 中可用,即使某些帧已失效,并且与将要使用的帧内帧相比,可以实现更好的图像质量NV_ENC_CONFIG_HEVC::maxNumRefFramesInDPB
。NV_ENC_CONFIG_AV1::maxNumRefFramesInDPB
在没有参考帧的情况下进行编码。
通过 API 失效的特定帧NvEncInvalidateRefFrames
是使用每个帧的唯一编号(称为时间戳)来标识的。这是在对图片进行编码时通过字段 NV_ENC_PIC_PARAMS::inputTimeStamp 发送到编码器的时间戳。这可以是任何单调递增的唯一数字。在其最常见的形式中,唯一编号可以是图片的呈现时间戳。编码器将帧存储在其 DPB 中,用作inputTimeStamp
唯一标识符,并在通过 API 请求时使用该标识符使相应的帧无效NvEncInvalidateRefFrames
。
帧内刷新
参考图片无效部分中描述的参考图片无效技术取决于带外上行通道在解码器(客户端)报告比特流错误的可用性。当这样的上行通道不可用时,或者在比特流更可能遭受更频繁错误的情况下,帧内刷新机制可以用作错误恢复机制。此外,当使用无限 GOP 长度时,不会传输任何帧内帧,并且帧内刷新可能是从传输错误中恢复的有用机制。
NVENCODE API提供了一种实现帧内刷新的机制。该enableIntraRefresh
标志应设置为 1 以启用内部刷新。intraRefreshPeriod
确定再次发生帧内刷新的时间段,并intraRefreshCnt
设置发生帧内刷新的帧数。
帧内刷新导致帧的连续部分在连续帧上使用帧内宏块进行编码intraRefreshCnt
。然后,整个循环intraRefreshPeriod
在第一个帧内刷新帧之后重复。必须根据传输过程中可能发生错误的概率intraRefreshPeriod
进行适当设置。intraRefreshCnt
例如,intraRefreshPeriod
对于高度容易出错的网络,可能很小,例如 30,从而能够每秒恢复 30 FPS 视频流。对于出错机会较小的网络,该值可以设置得更高。较低的值intraRefreshPeriod
会带来稍低的质量,因为帧内刷新周期内整体宏块的较大部分被迫进行帧内编码,但可以更快地从网络错误中恢复。
intraRefreshCnt
确定在帧内刷新周期内发生帧内刷新的帧数。较小的值将快速刷新整个帧(而不是在bandintraRefreshCnt
中缓慢刷新),从而实现更快的错误恢复。然而,较低也意味着每帧发送更多数量的帧内宏块,因此质量稍低。
默认的 NVENCODE API 帧内刷新行为对于 H.264/HEVC 是基于切片的,对于 AV1 是基于切片的,即帧内刷新波中的帧将具有多个切片/切片,其中一个切片/切片仅包含帧内编码的 MB/CTU/SB。
- 对于 AV1,内部刷新波期间使用的图块数量由驱动程序根据
intraRefreshCnt
和的值自动确定intraRefreshPeriod
。在帧内刷新波持续时间内,应用程序指定的任何自定义图块配置都将被忽略。 - 如果应用程序未明确指定切片数量,或者指定的切片数量小于 3,则在帧内刷新波期间,驱动程序将为每帧设置 3 个切片。
- 对于
NV_ENC_CONFIG_H264::sliceMode
= 0(基于 MB 的切片)、2(基于 MB 行的切片)和 3(切片数量),驱动程序将维护切片计数,等于以下最小值:根据切片模式设置计算的切片计数和帧内期间的切片intraRefreshCnt
数量刷新周期。 - 对于
NV_ENC_CONFIG_H264::sliceMode
= 1(基于字节的切片),帧内刷新波期间的切片数量始终为 3。
对于某些用例,客户可能希望避免帧中出现多个切片。在这种情况下,客户端可以启用单片内部刷新。
- 通过调用 API
NvEncGetEncodeCaps
并检查NV_ENC_CAPS_SINGLE_SLICE_INTRA_REFRESH
. NV_ENC_CONFIG_H264::singleSliceIntraRefresh
如果支持,可以通过设置/来启用单片内部刷新NV_ENC_CONFIG_HEVC::singleSliceIntraRefresh
。
如果在帧内刷新波中间出现分辨率重新配置,则正在进行的波将立即终止。下一波将在NV_ENC_CONFIG_H264::intraRefreshPeriod
帧数后开始。
帧内刷新按编码顺序应用,并且仅应用于可用作参考的帧。
HEVC 和 AV1 中的多 NVENC 分割帧编码
启用分割帧编码后,每个输入帧都会被分割为水平条带,这些水平条带由单独的 NVENC 独立且同时编码,与单个 NVENC 编码相比,通常会提高编码速度。
请注意以下事项:
- 尽管该功能提高了编码速度,但却降低了质量。
- 整体编码吞吐量(当所有NVENC都得到充分利用时,在某个时间间隔内编码的帧总数)将保持不变。
- 该功能仅适用于 HEVC 和 AV1。
因此,应使用此功能在单个编码会话中实现更高的编码速度,这在单个 NVENC 上是不可能的,因为特定输入流的水平条带在多个 NVENC 上同时编码。如上所述,当创建多个编码会话以充分利用所有 NVENC 时,此功能不会影响整体吞吐量。
有两种启用下面列出的功能的模式。
1. 自动模式:自动触发该功能的条件为:
- GPU 上的 NVENC 数量:2 个或更多。
- 帧高度:HEVC 必须为 2112 像素或更高,AV1 必须为 2048 像素或更高。
- 预设和调谐信息配置:表 2总结了启用分割帧编码的预设和调谐信息组合
调整信息 | 预设 | ||||||
---|---|---|---|---|---|---|---|
P1 | P2 | P3 | P4 | P5 | P6 | P7 | |
高质量 | 是的 | 是的 | 不 | 不 | 不 | 不 | 不 |
低延迟 | 是的 | 是的 | 是的 | 是的 | 不 | 不 | 不 |
超低延迟 | 是的 | 是的 | 是的 | 是的 | 不 | 不 | 不 |
2. 用户控制模式:
对于 HEVC 和 AV1,分割编码支持以下模式:
- NV_ENC_SPLIT_ENCODE_MODE::NV_ENC_SPLIT_AUTO_MODE:在此模式下,仅在上述配置中才会自动启用分割编码。它将在所有其他配置中被禁用。
- NV_ENC_SPLIT_ENCODE_MODE::NV_ENC_SPLIT_AUTO_FORCED_MODE:将为所有配置启用分割编码,并由驱动程序自动选择水平条带数量以获得最佳性能。
- NV_ENC_SPLIT_ENCODE_MODE::NV_ENC_SPLIT_TWO_FORCED_MODE:当 NVENC 数量 > 1 时,将为所有配置启用分割编码,水平条带数量强制为 2。
- NV_ENC_SPLIT_ENCODE_MODE::NV_ENC_SPLIT_THREE_FORCED_MODE:将为所有配置启用分割编码,当 NVENC 数量 > 2 时,水平条带数量强制为 3,否则为 NVENC 条带数量。
- NV_ENC_SPLIT_ENCODE_MODE::NV_ENC_SPLIT_DISABLE:所有配置都将禁用分割编码。
请注意,一些编码功能与分割帧编码的使用不兼容。当使用以下任何功能时,分割帧编码始终处于禁用状态:
- 加权预测(HEVC)。
- Alpha 层编码 (HEVC)。
- 比特流子帧读回模式 (HEVC)
- 视频内存中的比特流输出 (HEVC/AV1)
NVIDIA 硬件视频编码器在各种应用中具有多种用途。一些常见的应用包括:视频录制(存档)、游戏广播(在线广播/多播视频游戏)、转码(直播和视频点播)和流媒体(游戏或直播内容)。每个用例对质量、比特率、延迟容差、性能限制等都有其独特的要求。尽管 NVIDIA 编码器接口提供了通过许多 API 来控制设置的灵活性,但下表可用作建议设置的一般指南一些流行的用例可提供最佳的编码比特流质量。这些建议特别适用于基于第二代 Maxwell 架构的 GPU。对于早期的 GPU(Kepler 和第一代 Maxwell),建议客户使用表 3中的信息作为起点,并调整设置以实现适当的性能质量权衡。
用例 | 获得最佳质量和性能的推荐设置 |
---|---|
录音/存档 |
|
游戏铸造 & 云转码 |
|
低延迟用例,例如游戏流、视频会议等。 |
|
无损编码 |
|
*:推荐用于低动作游戏和自然视频。
**:推荐在第二代 Maxwell GPU 及更高版本上使用。
***:这些功能对于跨噪声介质传输期间的错误恢复非常有用。对于客户端需要减少视频内存占用的用例,应遵循以下准则。
- 避免使用 B 帧。B 帧需要额外的缓冲区来重新排序,因此避免使用 B 帧将节省视频内存使用量。
- 减少参考帧的最大数量。减少最大参考帧的数量会导致 NVIDIA 显示驱动程序在内部分配较少数量的缓冲区,从而减少视频内存占用。
- 使用单通道速率控制模式。由于第一遍编码的额外分配,与单遍相比,两遍速率控制会消耗额外的视频内存。全分辨率第一次通过的两次通过率控制模式比四分之一分辨率第一次通过的消耗更多。
- 避免自适应量化/加权预测。自适应量化/加权预测等功能会在视频内存中分配额外的缓冲区。如果不使用这些功能,则可以避免这些分配。
但请注意,上述准则可能会导致编码质量有所损失。因此,建议客户进行适当的评估,以在编码质量、速度和内存消耗之间取得适当的平衡。
注意
本文档仅供参考,不应被视为对产品特定功能、状况或质量的保证。NVIDIA Corporation(“NVIDIA”)对本文档中包含的信息的准确性或完整性不做任何明示或暗示的陈述或保证,并且对本文中包含的任何错误不承担任何责任。NVIDIA 对此类信息的后果或使用或因使用此类信息而可能导致的任何专利或第三方其他权利的侵犯不承担任何责任。本文档不承诺开发、发布或交付任何材料(定义如下)、代码或功能。
NVIDIA 保留随时对本文档进行更正、修改、增强、改进和任何其他更改的权利,恕不另行通知。
客户应在下订单前获取最新的相关信息,并应验证该等信息是最新且完整的。
NVIDIA 产品的销售须遵守订单确认时提供的 NVIDIA 标准销售条款和条件,除非 NVIDIA 授权代表与客户签署的个人销售协议(“销售条款”)中另有约定。NVIDIA 特此明确反对在购买本文档中引用的 NVIDIA 产品时应用任何客户一般条款和条件。本文件不直接或间接形成任何合同义务。
NVIDIA 产品并非设计、授权或保证适用于医疗、军事、飞机、太空或生命支持设备,也不适用于 NVIDIA 产品故障或故障可合理预期导致人身伤害的应用,死亡、财产或环境损害。NVIDIA 对于在此类设备或应用程序中包含和/或使用 NVIDIA 产品不承担任何责任,因此此类包含和/或使用的风险由客户自行承担。
NVIDIA 不声明或保证基于本文档的产品适合任何指定用途。每个产品的所有参数的测试不一定由 NVIDIA 进行。客户自行负责评估和确定本文档中包含的任何信息的适用性,确保产品适合并适合客户计划的应用,并对应用程序执行必要的测试,以避免应用程序出现故障或产品。客户产品设计中的缺陷可能会影响 NVIDIA 产品的质量和可靠性,并可能导致超出本文档中包含的条件和/或要求的其他或不同的条件和/或要求。对于可能基于或归因于以下原因的任何违约、损害、费用或问题,NVIDIA 不承担任何责任:(i) 以任何违反本文档的方式使用 NVIDIA 产品,或 (ii) 客户产品设计。
商标
NVIDIA、NVIDIA 徽标以及 cuBLAS、CUDA、CUDA Toolkit、cuDNN、DALI、DIGITS、DGX、DGX-1、DGX-2、DGX Station、DLProf、GPU、Jetson、Kepler、Maxwell、NCCL、Nsight Compute、Nsight Systems 、NVCaffe、NVIDIA 深度学习 SDK、NVIDIA 开发人员计划、NVIDIA GPU Cloud、NVLink、NVSHMEM、PerfWorks、Pascal、SDK Manager、Tegra、TensorRT、TensorRT 推理服务器、Tesla、TF-TRT、Triton 推理服务器、Turing 和 Volta 是NVIDIA Corporation 在美国和其他国家/地区的商标和/或注册商标。其他公司和产品名称可能是与其相关的各个公司的商标。
© 2010-2023 NVIDIA 公司。版权所有。 最后更新于 2023 年 4 月 20 日。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)