首页 > 解决方案 > 使用 GStreamer 和 NVENC 编码 OpenGL 纹理?

问题描述

我有一个将数据渲染成 rgba 纹理的 openGL 应用程序。我想使用 gstreamer 框架(使用 nvenc 插件进行 h264 编码)对其进行编码和流式传输。

我正在查看文档以解决这些问题:

  1. 如何将应用程序的现有 openGL 上下文导出到 nvenc 元素。
  2. 如何将纹理 ID 传递给来源?
  3. 同步将如何工作。即 nvenc 必须等待渲染完成,类似地,应用程序必须等待 nvenc 完成从纹理中读取。我假设它会涉及使用同步围栏或 glMemoryBarriers。

任何示例代码都会非常有帮助。

我确实想避免将任何纹理复制到 cpu 内存。Nvidia 的 NVENC sdk 提到它使用 CUDA 上下文进行调用,并且可以使用 cudaGraphicsGLRegisterImage 调用将 openGL 纹理导入到 CUDA 上下文中。所以我的期望是从应用程序到视频编码帧可以在没有任何副本的情况下完成。

标签: c++openglgstreamernvenc

解决方案


我知道这是一个老问题,但以防万一其他人遇到这个问题......

  1. 如果你的 NVENC 调用和 OpenGL 应用程序在同一个线程中,你不需要对上下文做任何事情。

    如果没有,您可能应该创建两个 OpenGL 上下文,一个用于渲染,一个用于编码。这两个上下文应该共享对象,如https://www.khronos.org/opengl/wiki/OpenGL_Context中所述。

    您还可以只创建一个上下文并通过将上下文设置为“当前”到访问 OpenGL 对象的线程来在线程之间传输上下文,但我发现这两个上下文更容易。

  2. 纹理 id 是一个整数,只需传递它。

  3. NvEncMapInputResource “提供同步保证在输入缓冲区上提交的任何图形或计算工作在缓冲区用于编码之前完成”。NvEncEncodePicture具有“同步编码模式”。

  4. 截至今天,NVENC 在 linux 上支持 OpenGL 编码设备,因此您不必在 CUDA 中注册 OpenGL 纹理。NVENC 可以直接访问 OpenGL 纹理,所以客户端没有内存拷贝。

    如果你在windows上工作,我相信你可以创建一个CUDA编码设备,然后从OpenGL纹理中获取一个CUarray,NVENC可以访问CUarray。

OpenGL 和 CUDA 编码设备的示例代码可以在 NVENC SDK 示例中找到。

编辑:

NvEncMapInputResource的同步保证似乎仅在单线程情况下(或在相同的 GL 上下文中?)。如果渲染和编码发生在不同的线程和上下文中,则必须在映射之前添加同步对象。


推荐阅读