Partially based on the work of Timo Rothenpieler <[email protected]>
---

Fix the profile mapping. Right now all our h264 encoders override the profile
setting so NVENC right now does the same, might be interesting to provide
some adapter to match avctx->profile to the internal profile variable.

 Changelog               |    1 +
 configure               |   16 +
 libavcodec/Makefile     |    3 +
 libavcodec/allcodecs.c  |    2 +
 libavcodec/nvenc.c      | 1139 +++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/nvenc.h      |  132 ++++++
 libavcodec/nvenc_h264.c |  110 +++++
 libavcodec/nvenc_hevc.c |  108 +++++
 libavcodec/version.h    |    2 +-
 9 files changed, 1512 insertions(+), 1 deletion(-)
 create mode 100644 libavcodec/nvenc.c
 create mode 100644 libavcodec/nvenc.h
 create mode 100644 libavcodec/nvenc_h264.c
 create mode 100644 libavcodec/nvenc_hevc.c

diff --git a/Changelog b/Changelog
index 41fe7c8..2c268ed 100644
--- a/Changelog
+++ b/Changelog
@@ -31,6 +31,7 @@ version <next>:
 - Canopus HQ/HQA decoder
 - Automatically rotate videos based on metadata in avconv
 - improved Quickdraw compatibility
+- NVIDIA NVENC-accelerated H.264 and HEVC encoding support


 version 11:
diff --git a/configure b/configure
index 863e33b..9870b6c 100755
--- a/configure
+++ b/configure
@@ -220,6 +220,7 @@ External library support:
   --enable-libxvid         enable Xvid encoding via xvidcore,
                            native MPEG-4/Xvid encoder exists [no]
   --enable-mmal            enable decoding via MMAL [no]
+  --enable-nvenc           enable encoding via NVENC [no]
   --enable-openssl         enable openssl [no]
   --enable-x11grab         enable X11 grabbing (legacy) [no]
   --enable-zlib            enable zlib [autodetect]
@@ -1189,6 +1190,7 @@ EXTERNAL_LIBRARY_LIST="
     libxcb_xfixes
     libxvid
     mmal
+    nvenc
     openssl
     x11grab
     zlib
@@ -1479,6 +1481,7 @@ SYSTEM_FUNCS="
     inet_aton
     isatty
     jack_port_get_latency_range
+    LoadLibrary
     localtime_r
     mach_absolute_time
     MapViewOfFile
@@ -1776,6 +1779,8 @@ mpegvideo_select="blockdsp hpeldsp idctdsp me_cmp 
videodsp"
 mpegvideoenc_select="me_cmp mpegvideo pixblockdsp qpeldsp"
 qsvdec_select="qsv"
 qsvenc_select="qsv"
+nvenc_if_any="dlopen LoadLibrary"
+nvenc_extralibs='$ldl'

 # decoders / encoders
 aac_decoder_select="imdct15 mdct sinewin"
@@ -1843,11 +1848,13 @@ h263i_decoder_select="h263_decoder"
 h263p_encoder_select="h263_encoder"
 h264_decoder_select="cabac golomb h264chroma h264dsp h264pred h264qpel 
startcode videodsp"
 h264_decoder_suggest="error_resilience"
+h264_nvenc_encoder_deps="nvenc"
 h264_qsv_decoder_deps="libmfx"
 h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec 
h264_qsv_hwaccel"
 h264_qsv_encoder_deps="libmfx"
 h264_qsv_encoder_select="qsvenc"
 hevc_decoder_select="bswapdsp cabac golomb videodsp"
+hevc_nvenc_encoder_deps="nvenc"
 huffyuv_decoder_select="bswapdsp huffyuvdsp"
 huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp"
 iac_decoder_select="imc_decoder"
@@ -3807,6 +3814,7 @@ die_license_disabled gpl x11grab

 die_license_disabled nonfree libfaac
 die_license_disabled nonfree libfdk_aac
+die_license_disabled nonfree nvenc
 die_license_disabled nonfree openssl

 die_license_disabled version3 libopencore_amrnb
@@ -4164,6 +4172,7 @@ check_func_headers windows.h CoTaskMemFree -lole32
 check_func_headers windows.h GetProcessAffinityMask
 check_func_headers windows.h GetProcessTimes
 check_func_headers windows.h GetSystemTimeAsFileTime
+check_func_headers windows.h LoadLibrary
 check_func_headers windows.h MapViewOfFile
 check_func_headers windows.h SetConsoleTextAttribute
 check_func_headers windows.h Sleep
@@ -4316,6 +4325,13 @@ if enabled libdc1394; then
     die "ERROR: No version of libdc1394 found "
 fi

+if enabled nvenc; then
+    check_header cuda.h || die "ERROR: cuda.h not found.";
+    check_header nvEncodeAPI.h || die "ERROR: nvEncodeAPI.h not found.";
+    check_cpp_condition nvEncodeAPI.h "NVENCAPI_MAJOR_VERSION >= 5" ||
+        die "ERROR: NVENC API version 4 or older is not supported";
+fi
+
 if check_pkg_config sdl SDL_events.h SDL_PollEvent; then
     check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | 
SDL_PATCHLEVEL) >= 0x010201" $sdl_cflags &&
     check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | 
SDL_PATCHLEVEL) < 0x010300" $sdl_cflags &&
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 0107460..e519c04 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -81,6 +81,7 @@ OBJS-$(CONFIG_MPEGVIDEOENC)            += mpegvideo_enc.o 
mpeg12data.o  \
                                           motion_est.o ratecontrol.o    \
                                           mpegvideoencdsp.o
 OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
+OBJS-${CONFIG_NVENC}                   += nvenc.o
 OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
 OBJS-$(CONFIG_QSV)                     += qsv.o
 OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
@@ -227,11 +228,13 @@ OBJS-$(CONFIG_H264_DECODER)            += h264.o 
h264_cabac.o h264_cavlc.o \
                                           h264_mb.o h264_picture.o h264_ps.o \
                                           h264_refs.o h264_sei.o h264_slice.o
 OBJS-$(CONFIG_H264_MMAL_DECODER)       += mmaldec.o
+OBJS-$(CONFIG_H264_NVENC_ENCODER)      += nvenc_h264.o
 OBJS-$(CONFIG_H264_QSV_DECODER)        += qsvdec_h264.o
 OBJS-$(CONFIG_H264_QSV_ENCODER)        += qsvenc_h264.o
 OBJS-$(CONFIG_HEVC_DECODER)            += hevc.o hevc_mvs.o hevc_ps.o 
hevc_sei.o \
                                           hevc_cabac.o hevc_refs.o hevcpred.o  
  \
                                           hevcdsp.o hevc_filter.o
+OBJS-$(CONFIG_HEVC_NVENC_ENCODER)      += nvenc_hevc.o
 OBJS-$(CONFIG_HNM4_VIDEO_DECODER)      += hnm4video.o
 OBJS-$(CONFIG_HQ_HQA_DECODER)          += hq_hqa.o hq_hqadata.o hq_hqadsp.o \
                                           canopus.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index a8b5b53..6b35f3e 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -471,7 +471,9 @@ void avcodec_register_all(void)
     REGISTER_ENCODER(LIBWAVPACK,        libwavpack);
     REGISTER_ENCODER(LIBWEBP,           libwebp);
     REGISTER_ENCODER(LIBX264,           libx264);
+    REGISTER_ENCODER(H264_NVENC,        h264_nvenc);
     REGISTER_ENCODER(LIBX265,           libx265);
+    REGISTER_ENCODER(HEVC_NVENC,        hevc_nvenc);
     REGISTER_ENCODER(LIBXAVS,           libxavs);
     REGISTER_ENCODER(LIBXVID,           libxvid);

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
new file mode 100644
index 0000000..8e19834
--- /dev/null
+++ b/libavcodec/nvenc.c
@@ -0,0 +1,1139 @@
+/*
+ * NVIDIA NVENC Support
+ * Copyright (C) 2015 Luca Barbato
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <cuda.h>
+#include <string.h>
+#include <nvEncodeAPI.h>
+
+#define CUDA_LIBNAME "libcuda.so"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+
+#define NVENC_LIBNAME "libnvidia-encode.so"
+
+#elif HAVE_WINDOWS_H
+#include <windows.h>
+
+#if ARCH_X86_64
+#define NVENC_LIBNAME "nvEncodeAPI64.dll"
+#else
+#define NVENC_LIBNAME "nvEncodeAPI.dll"
+#endif
+
+#define dlopen(filename, flags) LoadLibrary((filename))
+#define dlsym(handle, symbol)   GetProcAddress(handle, symbol)
+#define dlclose(handle)         FreeLibrary(handle)
+#endif
+
+#include "libavutil/common.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/mem.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "nvenc.h"
+
+#define NVENC_CAP 0x30
+#define BITSTREAM_BUFFER_SIZE 1024 * 1024
+
+#define LOAD_LIBRARY(l, path)                   \
+    do {                                        \
+        if (!((l) = dlopen(path, RTLD_LAZY))) { \
+            av_log(avctx, AV_LOG_ERROR,         \
+                   "Cannot load %s\n",          \
+                   path);                       \
+            return AVERROR_UNKNOWN;             \
+        }                                       \
+    } while (0)
+
+#define LOAD_SYMBOL(fun, lib, symbol)        \
+    do {                                     \
+        if (!((fun) = dlsym(lib, symbol))) { \
+            av_log(avctx, AV_LOG_ERROR,      \
+                   "Cannot load %s\n",       \
+                   symbol);                  \
+            return AVERROR_UNKNOWN;          \
+        }                                    \
+    } while (0)
+
+static av_cold int nvenc_load_libraries(AVCodecContext *avctx)
+{
+    NVENCContext *ctx         = avctx->priv_data;
+    NVENCLibraryContext *nvel = &ctx->nvel;
+    PNVENCODEAPICREATEINSTANCE nvenc_create_instance;
+
+    LOAD_LIBRARY(nvel->cuda, CUDA_LIBNAME);
+
+    LOAD_SYMBOL(nvel->cu_init, nvel->cuda, "cuInit");
+    LOAD_SYMBOL(nvel->cu_device_get_count, nvel->cuda, "cuDeviceGetCount");
+    LOAD_SYMBOL(nvel->cu_device_get, nvel->cuda, "cuDeviceGet");
+    LOAD_SYMBOL(nvel->cu_device_get_name, nvel->cuda, "cuDeviceGetName");
+    LOAD_SYMBOL(nvel->cu_device_compute_capability, nvel->cuda,
+                "cuDeviceComputeCapability");
+    LOAD_SYMBOL(nvel->cu_ctx_create, nvel->cuda, "cuCtxCreate_v2");
+    LOAD_SYMBOL(nvel->cu_ctx_pop_current, nvel->cuda, "cuCtxPopCurrent_v2");
+    LOAD_SYMBOL(nvel->cu_ctx_destroy, nvel->cuda, "cuCtxDestroy_v2");
+
+    LOAD_LIBRARY(nvel->nvenc, NVENC_LIBNAME);
+
+    LOAD_SYMBOL(nvenc_create_instance, nvel->nvenc,
+                "NvEncodeAPICreateInstance");
+
+    nvel->nvenc_funcs.version = NV_ENCODE_API_FUNCTION_LIST_VER;
+
+    if ((nvenc_create_instance(&nvel->nvenc_funcs)) != NV_ENC_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot create the NVENC instance");
+        return AVERROR_UNKNOWN;
+    }
+
+    return 0;
+}
+
+static int nvenc_open_session(AVCodecContext *avctx)
+{
+    NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = { 0 };
+    NVENCContext *ctx                           = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv             = &ctx->nvel.nvenc_funcs;
+    int ret;
+
+    params.version    = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
+    params.apiVersion = NVENCAPI_VERSION;
+    params.device     = ctx->cu_context;
+    params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
+
+    ret = nv->nvEncOpenEncodeSessionEx(&params, &ctx->nvenc_ctx);
+    if (ret != NV_ENC_SUCCESS) {
+        ctx->nvenc_ctx = NULL;
+        av_log(avctx, AV_LOG_ERROR,
+               "Cannot open the NVENC Session\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    return 0;
+}
+
+static int nvenc_check_codec_support(AVCodecContext *avctx)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
+    int i, ret, count = 0;
+    GUID *guids = NULL;
+
+    ret = nv->nvEncGetEncodeGUIDCount(ctx->nvenc_ctx, &count);
+
+    if (ret != NV_ENC_SUCCESS || !count)
+        return AVERROR(ENOSYS);
+
+    guids = av_malloc(count * sizeof(GUID));
+
+    ret = nv->nvEncGetEncodeGUIDs(ctx->nvenc_ctx, guids, count, &count);
+    if (ret != NV_ENC_SUCCESS) {
+        ret = AVERROR(ENOSYS);
+        goto fail;
+    }
+
+    ret = AVERROR(ENOSYS);
+    for (i = 0; i < count; i++) {
+        if (!memcmp(&guids[i], &ctx->params.encodeGUID, sizeof(*guids))) {
+            ret = 0;
+            break;
+        }
+    }
+
+fail:
+    av_free(guids);
+
+    return ret;
+}
+
+static int nvenc_check_cap(AVCodecContext *avctx, NV_ENC_CAPS cap)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
+    NV_ENC_CAPS_PARAM params        = { 0 };
+    int ret, val = 0;
+
+    params.version     = NV_ENC_CAPS_PARAM_VER;
+    params.capsToQuery = cap;
+
+    ret = nv->nvEncGetEncodeCaps(ctx->nvenc_ctx, ctx->params.encodeGUID, 
&params, &val);
+
+    if (ret == NV_ENC_SUCCESS)
+        return val;
+    return 0;
+}
+
+static int nvenc_check_capabilities(AVCodecContext *avctx)
+{
+    int ret;
+
+    ret = nvenc_check_codec_support(avctx);
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_VERBOSE, "Codec not supported\n");
+        return ret;
+    }
+
+    ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_YUV444_ENCODE);
+    if (avctx->pix_fmt == AV_PIX_FMT_YUV444P && ret <= 0) {
+        av_log(avctx, AV_LOG_VERBOSE, "YUV444P not supported\n");
+        return AVERROR(ENOSYS);
+    }
+
+    ret = nvenc_check_cap(avctx, NV_ENC_CAPS_WIDTH_MAX);
+    if (ret < avctx->width) {
+        av_log(avctx, AV_LOG_VERBOSE, "Width %d exceeds %d\n",
+               avctx->width, ret);
+        return AVERROR(ENOSYS);
+    }
+
+    ret = nvenc_check_cap(avctx, NV_ENC_CAPS_HEIGHT_MAX);
+    if (ret < avctx->height) {
+        av_log(avctx, AV_LOG_VERBOSE, "Height %d exceeds %d\n",
+               avctx->height, ret);
+        return AVERROR(ENOSYS);
+    }
+
+    ret = nvenc_check_cap(avctx, NV_ENC_CAPS_NUM_MAX_BFRAMES);
+    if (ret < avctx->max_b_frames) {
+        av_log(avctx, AV_LOG_VERBOSE, "Max b-frames %d exceed %d\n",
+               avctx->max_b_frames, ret);
+
+        return AVERROR(ENOSYS);
+    }
+
+    return 0;
+}
+
+static int nvenc_check_device(AVCodecContext *avctx, int idx)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NVENCLibraryContext *nvel       = &ctx->nvel;
+    char name[128]                  = { 0 };
+    int major, minor, ret;
+    CUdevice cu_device;
+    CUcontext dummy;
+    int loglevel = AV_LOG_VERBOSE;
+
+    if (ctx->device == LIST_DEVICES)
+        loglevel = AV_LOG_INFO;
+
+    ret = nvel->cu_device_get(&cu_device, idx);
+    if (ret != CUDA_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Cannot access the CUDA device %d\n",
+               idx);
+        return -1;
+    }
+
+    ret = nvel->cu_device_get_name(name, sizeof(name), cu_device);
+    if (ret != CUDA_SUCCESS)
+        return -1;
+
+    ret = nvel->cu_device_compute_capability(&major, &minor, cu_device);
+    if (ret != CUDA_SUCCESS)
+        return -1;
+
+    av_log(avctx, loglevel, "Device %d [%s] ", cu_device, name);
+
+    if (((major << 4) | minor) < NVENC_CAP)
+        goto fail;
+
+    ret = nvel->cu_ctx_create(&ctx->cu_context, 0, cu_device);
+    if (ret != CUDA_SUCCESS)
+        goto fail;
+
+    ret = nvel->cu_ctx_pop_current(&dummy);
+    if (ret != CUDA_SUCCESS)
+        goto fail2;
+
+    if ((ret = nvenc_open_session(avctx)) < 0)
+        goto fail2;
+
+    if ((ret = nvenc_check_capabilities(avctx)) < 0)
+        goto fail3;
+
+    av_log(avctx, loglevel, "supports NVENC\n");
+
+    if (ctx->device == cu_device || ctx->device == ANY_DEVICE)
+        return 0;
+
+fail3:
+    nvel->nvenc_funcs.nvEncDestroyEncoder(ctx->nvenc_ctx);
+    ctx->nvenc_ctx = NULL;
+
+fail2:
+    nvel->cu_ctx_destroy(ctx->cu_context);
+    ctx->cu_context = NULL;
+
+fail:
+    if (ret != 0)
+        av_log(avctx, loglevel, "does not support NVENC (major %d minor %d)\n",
+               major, minor);
+
+    return AVERROR(ENOSYS);
+}
+
+static int nvenc_setup_device(AVCodecContext *avctx)
+{
+    NVENCContext *ctx         = avctx->priv_data;
+    NVENCLibraryContext *nvel = &ctx->nvel;
+    int i, nb_devices = 0;
+
+    if ((nvel->cu_init(0)) != CUDA_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Cannot init CUDA\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    if ((nvel->cu_device_get_count(&nb_devices)) != CUDA_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Cannot enumerate the CUDA devices\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    switch (avctx->codec->id) {
+    case AV_CODEC_ID_H264:
+        ctx->params.encodeGUID = NV_ENC_CODEC_H264_GUID;
+        break;
+    case AV_CODEC_ID_HEVC:
+        ctx->params.encodeGUID = NV_ENC_CODEC_HEVC_GUID;
+        break;
+    default:
+        return AVERROR_BUG;
+    }
+
+    for (i = 0; i < nb_devices; ++i) {
+        if ((nvenc_check_device(avctx, i)) >= 0 && ctx->device != LIST_DEVICES)
+            return 0;
+    }
+
+    if (ctx->device == LIST_DEVICES)
+        return AVERROR_EXIT;
+
+    return AVERROR(ENOSYS);
+}
+
+typedef struct GUIDTuple {
+    const GUID guid;
+    int flags;
+} GUIDTuple;
+
+static int nvec_map_preset(NVENCContext *ctx)
+{
+    GUIDTuple presets[] = {
+        { NV_ENC_PRESET_DEFAULT_GUID },
+        { NV_ENC_PRESET_HP_GUID },
+        { NV_ENC_PRESET_HQ_GUID },
+        { NV_ENC_PRESET_BD_GUID },
+        { NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID, NVENC_LOWLATENCY },
+        { NV_ENC_PRESET_LOW_LATENCY_HP_GUID,      NVENC_LOWLATENCY },
+        { NV_ENC_PRESET_LOW_LATENCY_HQ_GUID,      NVENC_LOWLATENCY },
+        { NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID,    NVENC_LOSSLESS },
+        { NV_ENC_PRESET_LOSSLESS_HP_GUID,         NVENC_LOSSLESS },
+        { { 0 } }
+    };
+
+    GUIDTuple *t = &presets[ctx->preset];
+
+    ctx->params.presetGUID = t->guid;
+    ctx->flags             = t->flags;
+
+    return AVERROR(EINVAL);
+}
+
+static void set_constqp(AVCodecContext *avctx, NV_ENC_RC_PARAMS *rc)
+{
+    rc->rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
+    rc->constQP.qpInterB = avctx->global_quality;
+    rc->constQP.qpInterP = avctx->global_quality;
+    rc->constQP.qpIntra  = avctx->global_quality;
+}
+
+static void set_vbr(AVCodecContext *avctx, NV_ENC_RC_PARAMS *rc)
+{
+    if (avctx->qmin >= 0) {
+        rc->enableMinQP    = 1;
+        rc->minQP.qpInterB = avctx->qmin;
+        rc->minQP.qpInterP = avctx->qmin;
+        rc->minQP.qpIntra  = avctx->qmin;
+    }
+
+    if (avctx->qmax >= 0) {
+        rc->enableMaxQP = 1;
+        rc->maxQP.qpInterB = avctx->qmax;
+        rc->maxQP.qpInterP = avctx->qmax;
+        rc->maxQP.qpIntra  = avctx->qmax;
+    }
+}
+
+static void nvenc_override_rate_control(AVCodecContext *avctx,
+                                        NV_ENC_RC_PARAMS *rc)
+{
+    NVENCContext *ctx    = avctx->priv_data;
+
+    switch (ctx->rc) {
+    case NV_ENC_PARAMS_RC_CONSTQP:
+        if (avctx->global_quality < 0) {
+            av_log(avctx, AV_LOG_WARNING,
+                   "The constant quality rate-control requires "
+                   "the 'global_quality' option set.\n");
+            return;
+        }
+        set_constqp(avctx, rc);
+        return;
+    case NV_ENC_PARAMS_RC_2_PASS_VBR:
+    case NV_ENC_PARAMS_RC_VBR:
+        if (avctx->qmin < 0 && avctx->qmax < 0) {
+            av_log(avctx, AV_LOG_WARNING,
+                   "The variable bitrate rate-control requires "
+                   "the 'qmin' and/or 'qmax' option set.\n");
+            return;
+        }
+    case NV_ENC_PARAMS_RC_VBR_MINQP:
+        if (avctx->qmin < 0) {
+            av_log(avctx, AV_LOG_WARNING,
+                   "The variable bitrate rate-control requires "
+                   "the 'qmin' option set.\n");
+            return;
+        }
+        set_vbr(avctx, rc);
+        break;
+    case NV_ENC_PARAMS_RC_CBR:
+        break;
+    case NV_ENC_PARAMS_RC_2_PASS_QUALITY:
+    case NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP:
+        if (!(ctx->flags & NVENC_LOWLATENCY)) {
+            av_log(avctx, AV_LOG_WARNING,
+                   "The multipass rate-control requires "
+                   "a low-latency preset.\n");
+            return;
+        }
+    }
+
+    rc->rateControlMode = ctx->rc;
+}
+
+static void nvenc_setup_rate_control(AVCodecContext *avctx)
+{
+    NVENCContext *ctx    = avctx->priv_data;
+    NV_ENC_RC_PARAMS *rc = &ctx->config.rcParams;
+
+    if (avctx->bit_rate > 0)
+        rc->averageBitRate = avctx->bit_rate;
+
+    if (avctx->rc_max_rate > 0)
+        rc->maxBitRate = avctx->rc_max_rate;
+
+    if (ctx->rc > 0) {
+        nvenc_override_rate_control(avctx, rc);
+    } else if (avctx->global_quality > 0) {
+        set_constqp(avctx, rc);
+    } else if (avctx->qmin >= 0 && avctx->qmax >= 0) {
+        rc->rateControlMode = NV_ENC_PARAMS_RC_VBR;
+        set_vbr(avctx, rc);
+    }
+
+    if (avctx->rc_buffer_size > 0)
+        rc->vbvBufferSize = avctx->rc_buffer_size;
+
+    if (rc->averageBitRate > 0)
+        avctx->bit_rate = rc->averageBitRate;
+}
+
+static int nvenc_setup_h264_config(AVCodecContext *avctx)
+{
+    NVENCContext *ctx                      = avctx->priv_data;
+    NV_ENC_CONFIG *cc                      = &ctx->config;
+    NV_ENC_CONFIG_H264 *h264               = &cc->encodeCodecConfig.h264Config;
+    NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui = &h264->h264VUIParameters;
+
+    vui->colourDescriptionPresentFlag = 1;
+    vui->videoSignalTypePresentFlag   = 1;
+
+    vui->colourMatrix            = avctx->colorspace;
+    vui->colourPrimaries         = avctx->color_primaries;
+    vui->transferCharacteristics = avctx->color_trc;
+
+    vui->videoFullRangeFlag = avctx->color_range == AVCOL_RANGE_JPEG;
+
+    h264->disableSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 1 : 0;
+    h264->repeatSPSPPS  = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1;
+
+    h264->maxNumRefFrames = avctx->refs;
+    h264->idrPeriod       = cc->gopLength;
+
+    if (ctx->profile)
+        avctx->profile = ctx->profile;
+
+    if (avctx->pix_fmt == AV_PIX_FMT_YUV444P)
+        h264->chromaFormatIDC = 3;
+    else
+        h264->chromaFormatIDC = 1;
+
+    switch (ctx->profile) {
+    case NV_ENC_H264_PROFILE_BASELINE:
+        cc->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
+        break;
+    case NV_ENC_H264_PROFILE_MAIN:
+        cc->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
+        break;
+    case NV_ENC_H264_PROFILE_HIGH:
+        cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
+        break;
+    case NV_ENC_H264_PROFILE_HIGH_444:
+        cc->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID;
+        break;
+    case NV_ENC_H264_PROFILE_CONSTRAINED_HIGH:
+        cc->profileGUID = NV_ENC_H264_PROFILE_CONSTRAINED_HIGH_GUID;
+        break;
+    }
+
+    h264->level = ctx->level;
+
+    return 0;
+}
+
+static int nvenc_setup_hevc_config(AVCodecContext *avctx)
+{
+    NVENCContext *ctx                      = avctx->priv_data;
+    NV_ENC_CONFIG *cc                      = &ctx->config;
+    NV_ENC_CONFIG_HEVC *hevc               = &cc->encodeCodecConfig.hevcConfig;
+
+    hevc->disableSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 1 : 0;
+    hevc->repeatSPSPPS  = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1;
+
+    hevc->maxNumRefFramesInDPB = avctx->refs;
+    hevc->idrPeriod            = cc->gopLength;
+
+    /* No other profile is supported in the current SDK version 5 */
+    cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID;
+    avctx->profile  = FF_PROFILE_HEVC_MAIN;
+
+    if (ctx->level) {
+        hevc->level = ctx->level;
+    } else {
+        hevc->level = NV_ENC_LEVEL_AUTOSELECT;
+    }
+
+    if (ctx->tier) {
+        hevc->tier = ctx->tier;
+    }
+
+    return 0;
+}
+static int nvenc_setup_codec_config(AVCodecContext *avctx)
+{
+    switch (avctx->codec->id) {
+    case AV_CODEC_ID_H264:
+        return nvenc_setup_h264_config(avctx);
+    case AV_CODEC_ID_HEVC:
+        return nvenc_setup_hevc_config(avctx);
+    }
+    return 0;
+}
+
+static int nvenc_setup_encoder(AVCodecContext *avctx)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
+    NV_ENC_PRESET_CONFIG preset_cfg = { 0 };
+    int ret;
+
+    ctx->params.version = NV_ENC_INITIALIZE_PARAMS_VER;
+
+    ctx->params.encodeHeight = avctx->height;
+    ctx->params.encodeWidth  = avctx->width;
+
+    if (avctx->sample_aspect_ratio.num &&
+        avctx->sample_aspect_ratio.den &&
+        (avctx->sample_aspect_ratio.num != 1 ||
+         avctx->sample_aspect_ratio.num != 1)) {
+        av_reduce(&ctx->params.darWidth,
+                  &ctx->params.darHeight,
+                  avctx->width * avctx->sample_aspect_ratio.num,
+                  avctx->height * avctx->sample_aspect_ratio.den,
+                  INT_MAX / 8);
+    } else {
+        ctx->params.darHeight = avctx->height;
+        ctx->params.darWidth  = avctx->width;
+    }
+
+    ctx->params.frameRateNum = avctx->time_base.den;
+    ctx->params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
+
+    ctx->params.enableEncodeAsync = 0;
+    ctx->params.enablePTD         = 1;
+
+    ctx->params.encodeConfig = &ctx->config;
+
+    nvec_map_preset(ctx);
+
+    preset_cfg.version           = NV_ENC_PRESET_CONFIG_VER;
+    preset_cfg.presetCfg.version = NV_ENC_CONFIG_VER;
+
+    ret = nv->nvEncGetEncodePresetConfig(ctx->nvenc_ctx,
+                                         ctx->params.encodeGUID,
+                                         ctx->params.presetGUID,
+                                         &preset_cfg);
+    if (ret != NV_ENC_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Cannot get the preset configuration\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    memcpy(&ctx->config, &preset_cfg.presetCfg, sizeof(ctx->config));
+
+    ctx->config.version = NV_ENC_CONFIG_VER;
+
+    if (avctx->gop_size > 0) {
+        if (avctx->max_b_frames > 0) {
+            ctx->last_dts = -2;
+            /* 0 is intra-only,
+             * 1 is I/P only,
+             * 2 is one B Frame,
+             * 3 two B frames, and so on. */
+            ctx->config.frameIntervalP = avctx->max_b_frames + 1;
+        } else if (avctx->max_b_frames == 0) {
+            ctx->config.frameIntervalP = 1;
+        }
+        ctx->config.gopLength = avctx->gop_size;
+    } else if (avctx->gop_size == 0) {
+        ctx->config.frameIntervalP = 0;
+        ctx->config.gopLength      = 1;
+    }
+
+    if (ctx->config.frameIntervalP > 1)
+        avctx->max_b_frames = ctx->config.frameIntervalP - 1;
+
+    nvenc_setup_rate_control(avctx);
+
+    if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
+        ctx->config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
+    } else {
+        ctx->config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
+    }
+
+    if ((ret = nvenc_setup_codec_config(avctx)) < 0)
+        return ret;
+
+    ret = nv->nvEncInitializeEncoder(ctx->nvenc_ctx, &ctx->params);
+    if (ret != NV_ENC_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot initialize the decoder");
+        return AVERROR_UNKNOWN;
+    }
+
+    return 0;
+}
+
+static int nvenc_alloc_surface(AVCodecContext *avctx, int idx)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
+    int ret;
+    NV_ENC_CREATE_INPUT_BUFFER in_buffer      = { 0 };
+    NV_ENC_CREATE_BITSTREAM_BUFFER out_buffer = { 0 };
+
+    in_buffer.version  = NV_ENC_CREATE_INPUT_BUFFER_VER;
+    out_buffer.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
+
+    in_buffer.width  = avctx->width;
+    in_buffer.height = avctx->height;
+
+    in_buffer.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_UNCACHED;
+
+    switch (avctx->pix_fmt) {
+    case AV_PIX_FMT_YUV420P:
+        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_YV12_PL;
+        break;
+    case AV_PIX_FMT_NV12:
+        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12_PL;
+        break;
+    case AV_PIX_FMT_YUV444P:
+        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_YUV444_PL;
+        break;
+    default:
+        return AVERROR_BUG;
+    }
+
+    ret = nv->nvEncCreateInputBuffer(ctx->nvenc_ctx, &in_buffer);
+    if (ret != NV_ENC_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR, "CreateInputBuffer failed\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    ctx->in[idx].in        = in_buffer.inputBuffer;
+    ctx->in[idx].format    = in_buffer.bufferFmt;
+
+    /* 1MB is large enough to hold most output frames.
+     * NVENC increases this automaticaly if it's not enough. */
+    out_buffer.size = BITSTREAM_BUFFER_SIZE;
+
+    out_buffer.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_UNCACHED;
+
+    ret = nv->nvEncCreateBitstreamBuffer(ctx->nvenc_ctx, &out_buffer);
+    if (ret != NV_ENC_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR, "CreateBitstreamBuffer failed\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    ctx->out[idx].out  = out_buffer.bitstreamBuffer;
+    ctx->out[idx].busy = 0;
+
+    return 0;
+}
+
+static int nvenc_setup_surfaces(AVCodecContext *avctx)
+{
+    NVENCContext *ctx = avctx->priv_data;
+    int i, ret;
+
+    ctx->nb_surfaces = FFMAX(4 + avctx->max_b_frames,
+                             ctx->nb_surfaces);
+
+    ctx->in = av_mallocz(ctx->nb_surfaces * sizeof(*ctx->in));
+    if (!ctx->in)
+        return AVERROR(ENOMEM);
+
+    ctx->out = av_mallocz(ctx->nb_surfaces * sizeof(*ctx->out));
+    if (!ctx->out)
+        return AVERROR(ENOMEM);
+
+    ctx->timestamps = av_fifo_alloc(ctx->nb_surfaces * sizeof(int64_t));
+    if (!ctx->timestamps)
+        return AVERROR(ENOMEM);
+    ctx->pending = av_fifo_alloc(ctx->nb_surfaces * sizeof(ctx->out));
+    if (!ctx->pending)
+        return AVERROR(ENOMEM);
+    ctx->ready = av_fifo_alloc(ctx->nb_surfaces * sizeof(ctx->out));
+    if (!ctx->ready)
+        return AVERROR(ENOMEM);
+
+    for (i = 0; i < ctx->nb_surfaces; i++) {
+        if ((ret = nvenc_alloc_surface(avctx, i)) < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+#define EXTRADATA_SIZE 512
+
+static int nvenc_setup_extradata(AVCodecContext *avctx)
+{
+    NVENCContext *ctx                     = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv       = &ctx->nvel.nvenc_funcs;
+    NV_ENC_SEQUENCE_PARAM_PAYLOAD payload = { 0 };
+    int ret;
+
+    avctx->extradata = av_mallocz(EXTRADATA_SIZE + 
FF_INPUT_BUFFER_PADDING_SIZE);
+    if (!avctx->extradata)
+        return AVERROR(ENOMEM);
+
+    payload.version              = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER;
+    payload.spsppsBuffer         = avctx->extradata;
+    payload.inBufferSize         = EXTRADATA_SIZE;
+    payload.outSPSPPSPayloadSize = &avctx->extradata_size;
+
+    ret = nv->nvEncGetSequenceParams(ctx->nvenc_ctx, &payload);
+    if (ret != NV_ENC_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot get the extradata\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    return 0;
+}
+
+av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
+    int i;
+
+    av_frame_free(&avctx->coded_frame);
+
+    if (ctx->in) {
+        for (i = 0; i < ctx->nb_surfaces; ++i) {
+            nv->nvEncDestroyInputBuffer(ctx->nvenc_ctx, ctx->in[i].in);
+            nv->nvEncDestroyBitstreamBuffer(ctx->nvenc_ctx, ctx->out[i].out);
+        }
+    }
+
+    av_freep(&ctx->in);
+    av_freep(&ctx->out);
+
+    if (ctx->nvenc_ctx)
+        nv->nvEncDestroyEncoder(ctx->nvenc_ctx);
+
+    if (ctx->cu_context)
+        ctx->nvel.cu_ctx_destroy(ctx->cu_context);
+
+    if (ctx->nvel.nvenc)
+        dlclose(ctx->nvel.nvenc);
+
+    if (ctx->nvel.cuda)
+        dlclose(ctx->nvel.cuda);
+
+    return 0;
+}
+
+av_cold int ff_nvenc_encode_init(AVCodecContext *avctx)
+{
+    int ret;
+
+    if ((ret = nvenc_load_libraries(avctx)) < 0)
+        return ret;
+
+    if ((ret = nvenc_setup_device(avctx)) < 0)
+        return ret;
+
+    if ((ret = nvenc_setup_encoder(avctx)) < 0)
+        return ret;
+
+    if ((ret = nvenc_setup_surfaces(avctx)) < 0)
+        return ret;
+
+    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
+        if ((ret = nvenc_setup_extradata(avctx)) < 0)
+            return ret;
+    }
+
+    avctx->coded_frame = av_frame_alloc();
+    if (!avctx->coded_frame)
+        return AVERROR(ENOMEM);
+
+    return 0;
+}
+
+static NVENCInputSurface *get_input_surface(NVENCContext *ctx)
+{
+    int i;
+
+    for (i = 0; i < ctx->nb_surfaces; i++) {
+        if (!ctx->in[i].locked) {
+            ctx->in[i].locked = 1;
+            return &ctx->in[i];
+        }
+    }
+
+    return NULL;
+}
+
+static NVENCOutputSurface *get_output_surface(NVENCContext *ctx)
+{
+    int i;
+
+    for (i = 0; i < ctx->nb_surfaces; i++) {
+        if (!ctx->out[i].busy) {
+            return &ctx->out[i];
+        }
+    }
+
+    abort();
+    return NULL;
+}
+
+static int nvenc_copy_frame(NV_ENC_LOCK_INPUT_BUFFER *in, const AVFrame *frame)
+{
+    uint8_t *buf = in->bufferDataPtr;
+    int off      = frame->height * in->pitch;
+
+    switch (frame->format) {
+    case AV_PIX_FMT_YUV420P:
+        av_image_copy_plane(buf, in->pitch,
+                            frame->data[0], frame->linesize[0],
+                            frame->width, frame->height);
+        buf += off;
+
+        av_image_copy_plane(buf, in->pitch >> 1,
+                            frame->data[2], frame->linesize[2],
+                            frame->width >> 1, frame->height >> 1);
+
+        buf += off >> 2;
+
+        av_image_copy_plane(buf, in->pitch >> 1,
+                            frame->data[1], frame->linesize[1],
+                            frame->width >> 1, frame->height >> 1);
+        break;
+    case AV_PIX_FMT_NV12:
+        av_image_copy_plane(buf, in->pitch,
+                            frame->data[0], frame->linesize[0],
+                            frame->width, frame->height);
+        buf += off;
+
+        av_image_copy_plane(buf, in->pitch >> 1,
+                            frame->data[1], frame->linesize[1],
+                            frame->width >> 1, frame->height >> 1);
+        break;
+    case AV_PIX_FMT_YUV444P:
+        av_image_copy_plane(buf, in->pitch,
+                            frame->data[0], frame->linesize[0],
+                            frame->width, frame->height);
+        buf += off;
+
+        av_image_copy_plane(buf, in->pitch,
+                            frame->data[1], frame->linesize[1],
+                            frame->width, frame->height);
+        buf += off;
+
+        av_image_copy_plane(buf, in->pitch,
+                            frame->data[2], frame->linesize[2],
+                            frame->width, frame->height);
+        break;
+    default:
+        return AVERROR_BUG;
+    }
+
+    return 0;
+}
+
+static int nvenc_enqueue_frame(AVCodecContext *avctx, const AVFrame *frame,
+                               NVENCInputSurface **in_surf)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
+    NV_ENC_LOCK_INPUT_BUFFER params = { 0 };
+    NVENCInputSurface *in           = get_input_surface(ctx);
+    int ret;
+
+    if (!in)
+        return AVERROR_BUG;
+
+    params.version     = NV_ENC_LOCK_INPUT_BUFFER_VER;
+    params.inputBuffer = in->in;
+
+
+    ret = nv->nvEncLockInputBuffer(ctx->nvenc_ctx, &params);
+    if (ret != NV_ENC_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot lock the buffer %p.\n",
+               in);
+        return AVERROR_UNKNOWN;
+    }
+
+    ret = nvenc_copy_frame(&params, frame);
+    if (ret < 0)
+        goto fail;
+
+    ret = nv->nvEncUnlockInputBuffer(ctx->nvenc_ctx, in->in);
+    if (ret != NV_ENC_SUCCESS) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot unlock the buffer %p.\n",
+               in);
+        return AVERROR_UNKNOWN;
+    }
+
+    *in_surf = in;
+
+    return 0;
+
+fail:
+    nv->nvEncUnlockInputBuffer(ctx->nvenc_ctx, in->in);
+
+    return ret;
+}
+
+static void nvenc_codec_specific_pic_params(AVCodecContext *avctx,
+                                            NV_ENC_PIC_PARAMS *params)
+{
+    NVENCContext *ctx = avctx->priv_data;
+
+    switch (avctx->codec->id) {
+    case AV_CODEC_ID_H264:
+        params->codecPicParams.h264PicParams.sliceMode =
+            ctx->config.encodeCodecConfig.h264Config.sliceMode;
+        params->codecPicParams.h264PicParams.sliceModeData =
+            ctx->config.encodeCodecConfig.h264Config.sliceModeData;
+        break;
+    case AV_CODEC_ID_HEVC:
+        params->codecPicParams.hevcPicParams.sliceMode =
+            ctx->config.encodeCodecConfig.hevcConfig.sliceMode;
+        params->codecPicParams.hevcPicParams.sliceModeData =
+            ctx->config.encodeCodecConfig.hevcConfig.sliceModeData;
+        break;
+    }
+}
+
+static inline int nvenc_enqueue_timestamp(AVFifoBuffer *f, int64_t pts)
+{
+    return av_fifo_generic_write(f, &pts, sizeof(pts), NULL);
+}
+
+static inline int nvenc_dequeue_timestamp(AVFifoBuffer *f, int64_t *pts)
+{
+    return av_fifo_generic_read(f, pts, sizeof(*pts), NULL);
+}
+
+static inline int nvenc_enqueue_surface(AVFifoBuffer *f,
+                                        NVENCOutputSurface *surf)
+{
+    surf->busy = 1;
+    return av_fifo_generic_write(f, &surf, sizeof(surf), NULL);
+}
+
+static inline int nvenc_dequeue_surface(AVFifoBuffer *f,
+                                        NVENCOutputSurface **surf)
+{
+    return av_fifo_generic_read(f, surf, sizeof(*surf), NULL);
+}
+
+static int nvenc_set_timestamp(NVENCContext *ctx,
+                               NV_ENC_LOCK_BITSTREAM *params,
+                               AVPacket *pkt)
+{
+    int ret;
+
+    pkt->pts      = params->outputTimeStamp;
+    pkt->duration = params->outputDuration;
+
+    ret = nvenc_dequeue_timestamp(ctx->timestamps, &pkt->dts);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int nvenc_get_frame(AVCodecContext *avctx, AVPacket *pkt)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
+    NV_ENC_LOCK_BITSTREAM params    = { 0 };
+    NVENCOutputSurface *out         = NULL;
+    int ret;
+
+    ret = nvenc_dequeue_surface(ctx->pending, &out);
+    if (ret)
+        return ret;
+
+    params.version         = NV_ENC_LOCK_BITSTREAM_VER;
+    params.outputBitstream = out->out;
+
+    ret = nv->nvEncLockBitstream(ctx->nvenc_ctx, &params);
+    if (ret < 0)
+        return AVERROR_UNKNOWN;
+
+    ret = ff_alloc_packet(pkt, params.bitstreamSizeInBytes);
+    if (ret < 0)
+        return ret;
+
+    memcpy(pkt->data, params.bitstreamBufferPtr, pkt->size);
+
+    ret = nv->nvEncUnlockBitstream(ctx->nvenc_ctx, out->out);
+    if (ret < 0)
+        return AVERROR_UNKNOWN;
+
+    out->busy = out->in->locked = 0;
+
+    nvenc_set_timestamp(ctx, &params, pkt);
+
+    switch (params.pictureType) {
+    case NV_ENC_PIC_TYPE_IDR:
+        pkt->flags |= AV_PKT_FLAG_KEY;
+    case NV_ENC_PIC_TYPE_INTRA_REFRESH:
+    case NV_ENC_PIC_TYPE_I:
+        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+        break;
+    case NV_ENC_PIC_TYPE_P:
+        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_P;
+        break;
+    case NV_ENC_PIC_TYPE_B:
+        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_B;
+        break;
+    case NV_ENC_PIC_TYPE_BI:
+        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_BI;
+        break;
+    }
+
+    return 0;
+}
+
+int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+                          const AVFrame *frame, int *got_packet)
+{
+    NVENCContext *ctx               = avctx->priv_data;
+    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
+    NV_ENC_PIC_PARAMS params        = { 0 };
+    NVENCInputSurface *in           = NULL;
+    NVENCOutputSurface *out         = NULL;
+    int ret;
+
+    params.version = NV_ENC_PIC_PARAMS_VER;
+
+    if (frame) {
+        ret = nvenc_enqueue_frame(avctx, frame, &in);
+        if (ret < 0)
+            return ret;
+        out = get_output_surface(ctx);
+        if (!out)
+            return AVERROR_BUG;
+
+        out->in = in;
+
+        params.inputBuffer     = in->in;
+        params.bufferFmt       = in->format;
+        params.inputWidth      = frame->width;
+        params.inputHeight     = frame->height;
+        params.outputBitstream = out->out;
+        params.inputTimeStamp  = frame->pts;
+
+        if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
+            if (frame->top_field_first)
+                params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
+            else
+                params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
+        } else {
+            params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
+        }
+
+        nvenc_codec_specific_pic_params(avctx, &params);
+
+        ret = nvenc_enqueue_timestamp(ctx->timestamps, frame->pts);
+        if (ret < 0)
+            return ret;
+    } else {
+        params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
+    }
+
+    ret = nv->nvEncEncodePicture(ctx->nvenc_ctx, &params);
+
+    if (ret != NV_ENC_SUCCESS &&
+        ret != NV_ENC_ERR_NEED_MORE_INPUT) {
+
+        return AVERROR_UNKNOWN;
+    }
+
+    if (out) {
+        ret = nvenc_enqueue_surface(ctx->pending, out);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (ret != NV_ENC_ERR_NEED_MORE_INPUT &&
+        av_fifo_size(ctx->pending)) {
+        ret = nvenc_get_frame(avctx, pkt);
+        if (ret < 0)
+            return ret;
+        *got_packet = 1;
+    } else {
+        *got_packet = 0;
+    }
+
+    return 0;
+}
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
new file mode 100644
index 0000000..513339f
--- /dev/null
+++ b/libavcodec/nvenc.h
@@ -0,0 +1,132 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_NVENC_H
+#define AVCODEC_NVENC_H
+
+#include <cuda.h>
+#include <nvEncodeAPI.h>
+
+#include "libavutil/fifo.h"
+
+typedef struct NVENCInputSurface {
+    NV_ENC_INPUT_PTR in;
+    NV_ENC_BUFFER_FORMAT format;
+    int locked;
+} NVENCInputSurface;
+
+typedef struct NVENCOutputSurface {
+    NV_ENC_OUTPUT_PTR out;
+    NVENCInputSurface *in;
+    int busy;
+} NVENCOutputSurface;
+
+typedef CUresult(CUDAAPI *PCUINIT)(unsigned int Flags);
+typedef CUresult(CUDAAPI *PCUDEVICEGETCOUNT)(int *count);
+typedef CUresult(CUDAAPI *PCUDEVICEGET)(CUdevice *device, int ordinal);
+typedef CUresult(CUDAAPI *PCUDEVICEGETNAME)(char *name, int len, CUdevice dev);
+typedef CUresult(CUDAAPI *PCUDEVICECOMPUTECAPABILITY)(int *major, int *minor, 
CUdevice dev);
+typedef CUresult(CUDAAPI *PCUCTXCREATE)(CUcontext *pctx, unsigned int flags, 
CUdevice dev);
+typedef CUresult(CUDAAPI *PCUCTXPOPCURRENT)(CUcontext *pctx);
+typedef CUresult(CUDAAPI *PCUCTXDESTROY)(CUcontext ctx);
+
+typedef NVENCSTATUS (NVENCAPI* 
PNVENCODEAPICREATEINSTANCE)(NV_ENCODE_API_FUNCTION_LIST *functionList);
+
+typedef struct NVENCLibraryContext
+{
+    void *cuda;
+    void *nvenc;
+
+    PCUINIT cu_init;
+    PCUDEVICEGETCOUNT cu_device_get_count;
+    PCUDEVICEGET cu_device_get;
+    PCUDEVICEGETNAME cu_device_get_name;
+    PCUDEVICECOMPUTECAPABILITY cu_device_compute_capability;
+    PCUCTXCREATE cu_ctx_create;
+    PCUCTXPOPCURRENT cu_ctx_pop_current;
+    PCUCTXDESTROY cu_ctx_destroy;
+
+    NV_ENCODE_API_FUNCTION_LIST nvenc_funcs;
+} NVENCLibraryContext;
+
+enum {
+    PRESET_DEFAULT,
+    PRESET_HP,
+    PRESET_HQ,
+    PRESET_BD ,
+    PRESET_LOW_LATENCY_DEFAULT ,
+    PRESET_LOW_LATENCY_HQ ,
+    PRESET_LOW_LATENCY_HP,
+    PRESET_LOSSLESS_DEFAULT,
+    PRESET_LOSSLESS_HP,
+};
+
+enum {
+    NV_ENC_H264_PROFILE_BASELINE,
+    NV_ENC_H264_PROFILE_MAIN,
+    NV_ENC_H264_PROFILE_HIGH,
+    NV_ENC_H264_PROFILE_HIGH_444,
+    NV_ENC_H264_PROFILE_CONSTRAINED_HIGH,
+};
+
+enum {
+    NVENC_LOWLATENCY = 1,
+    NVENC_LOSSLESS,
+};
+
+enum {
+    LIST_DEVICES = -2,
+    ANY_DEVICE,
+};
+
+typedef struct NVENCContext {
+    AVClass *class;
+    NVENCLibraryContext nvel;
+
+    NV_ENC_INITIALIZE_PARAMS params;
+    NV_ENC_CONFIG config;
+
+    CUcontext cu_context;
+
+    int nb_surfaces;
+    NVENCInputSurface *in;
+    NVENCOutputSurface *out;
+    AVFifoBuffer *timestamps;
+    AVFifoBuffer *pending, *ready;
+
+    int64_t last_dts;
+
+    void *nvenc_ctx;
+
+    int preset;
+    int profile;
+    int level;
+    int tier;
+    int rc;
+    int device;
+    int flags;
+} NVENCContext;
+
+int ff_nvenc_encode_init(AVCodecContext *avctx);
+
+int ff_nvenc_encode_close(AVCodecContext *avctx);
+
+int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+                          const AVFrame *frame, int *got_packet);
+
+#endif /* AVCODEC_NVENC_H */
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
new file mode 100644
index 0000000..f94f670
--- /dev/null
+++ b/libavcodec/nvenc_h264.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/internal.h"
+#include "libavutil/opt.h"
+
+#include "avcodec.h"
+#include "internal.h"
+
+#include "nvenc.h"
+
+#define OFFSET(x) offsetof(NVENCContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    { "preset",   "Set the encoding preset",              OFFSET(preset),      
AV_OPT_TYPE_INT,    { .i64 = PRESET_HQ }, PRESET_DEFAULT, PRESET_LOSSLESS_HP, 
VE, "preset" },
+    { "default",    "",                                   0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_DEFAULT }, 0, 0, VE, "preset" },
+    { "hp",         "",                                   0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_HP }, 0, 0, VE, "preset" },
+    { "hq",         "",                                   0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_HQ }, 0, 0, VE, "preset" },
+    { "bd",         "",                                   0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_BD }, 0, 0, VE, "preset" },
+    { "ll",         "low latency",                        0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_LOW_LATENCY_DEFAULT }, 0, 0, VE, "preset" },
+    { "llhq",       "low latency hq",                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_LOW_LATENCY_HQ }, 0, 0, VE, "preset" },
+    { "llhp",       "low latency hp",                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_LOW_LATENCY_HP }, 0, 0, VE, "preset" },
+    { "profile",  "Set the encoding profile",             OFFSET(profile),     
AV_OPT_TYPE_INT,    { .i64 = NV_ENC_H264_PROFILE_HIGH }, 
NV_ENC_H264_PROFILE_BASELINE, NV_ENC_H264_PROFILE_CONSTRAINED_HIGH, VE, 
"profile" },
+    { "baseline", "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_H264_PROFILE_BASELINE },            0, 0, 
VE, "profile" },
+    { "main",     "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_H264_PROFILE_MAIN },                0, 0, 
VE, "profile" },
+    { "high",     "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_H264_PROFILE_HIGH },                0, 0, 
VE, "profile" },
+    { "high_444", "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_H264_PROFILE_HIGH_444 },            0, 0, 
VE, "profile" },
+    { "constrained_high", "",                             0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_H264_PROFILE_CONSTRAINED_HIGH },    0, 0, 
VE, "profile" },
+    { "level",    "Set the encoding level restriction",   OFFSET(level),       
AV_OPT_TYPE_INT,    { .i64 = NV_ENC_LEVEL_AUTOSELECT }, 
NV_ENC_LEVEL_AUTOSELECT, NV_ENC_LEVEL_H264_51, VE, "level" },
+    { "1.0",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_1 },  0, 0, VE,  "level" },
+    { "1.b",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_1b }, 0, 0, VE,  "level" },
+    { "1.1",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_11 }, 0, 0, VE,  "level" },
+    { "1.2",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_12 }, 0, 0, VE,  "level" },
+    { "1.3",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_13 }, 0, 0, VE,  "level" },
+    { "2.0",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_2 },  0, 0, VE,  "level" },
+    { "2.1",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_21 }, 0, 0, VE,  "level" },
+    { "2.2",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_22 }, 0, 0, VE,  "level" },
+    { "3.0",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_3 },  0, 0, VE,  "level" },
+    { "3.1",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_31 }, 0, 0, VE,  "level" },
+    { "3.2",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_32 }, 0, 0, VE,  "level" },
+    { "4.0",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_4 },  0, 0, VE,  "level" },
+    { "4.1",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_41 }, 0, 0, VE,  "level" },
+    { "4.2",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_42 }, 0, 0, VE,  "level" },
+    { "5.0",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_5 },  0, 0, VE,  "level" },
+    { "5.1",      "",                                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_H264_51 }, 0, 0, VE,  "level" },
+    { "rc",       "Override the preset rate-control",     OFFSET(rc),          
AV_OPT_TYPE_INT,    { .i64 = -1 },                   -1, 0, VE },
+    { "constqp",          "Constant QP mode",                                  
                          0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_CONSTQP },              0, 0, VE, "rc" },
+    { "vbr",              "Variable bitrate mode",                             
                          0, AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_PARAMS_RC_VBR 
},                  0, 0, VE, "rc" },
+    { "cbr",              "Constant bitrate mode",                             
                          0, AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_PARAMS_RC_CBR 
},                  0, 0, VE, "rc" },
+    { "vbr_minqp",        "Variable bitrate mode with MinQP",                  
                          0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_VBR_MINQP },            0, 0, VE, "rc" },
+    { "ll_2pass_quality", "Multi-pass optimized for image quality (only for 
low-latency presets)",       0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_2_PASS_QUALITY },       0, 0, VE, "rc" },
+    { "ll_2pass_size",    "Multi-pass optimized for constant frame size (only 
for low-latency presets)", 0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP }, 0, 0, VE, "rc" },
+    { "vbr_2pass",        "Multi-pass variable bitrate mode",                  
                          0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_2_PASS_VBR },           0, 0, VE, "rc" },
+    { "surfaces", "Number of concurrent surfaces",        OFFSET(nb_surfaces), 
AV_OPT_TYPE_INT,    { .i64 = 32 },                   0, INT_MAX, VE },
+    { "device",   "Select a specific NVENC device",       OFFSET(device),      
AV_OPT_TYPE_INT,    { .i64 = -1 },                   -2, INT_MAX, VE, "device" 
},
+    { "any",      "Pick the first device available",      0,                   
AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "device" },
+    { "list",     "List the available devices",           0,                   
AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "device" },
+    { NULL }
+};
+
+static const AVClass nvenc_hevc_class = {
+    .class_name = "nvenc_h264",
+    .item_name = av_default_item_name,
+    .option = options,
+    .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVCodecDefault defaults[] = {
+    { "b", "0" },
+    { "qmin", "-1" },
+    { "qmax", "-1" },
+    { "qdiff", "-1" },
+    { "qblur", "-1" },
+    { "qcomp", "-1" },
+    { NULL },
+};
+
+AVCodec ff_h264_nvenc_encoder = {
+    .name           = "nvenc_h264",
+    .long_name      = NULL_IF_CONFIG_SMALL("NVIDIA NVENC H264 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),
+    .priv_class     = &nvenc_hevc_class,
+    .defaults       = defaults,
+    .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12,
+                                                    AV_PIX_FMT_YUV420P,
+                                                    AV_PIX_FMT_YUV444P,
+                                                    AV_PIX_FMT_NONE },
+    .capabilities   = CODEC_CAP_DELAY,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
new file mode 100644
index 0000000..a862428
--- /dev/null
+++ b/libavcodec/nvenc_hevc.c
@@ -0,0 +1,108 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/internal.h"
+#include "libavutil/opt.h"
+
+#include "avcodec.h"
+#include "internal.h"
+
+#include "nvenc.h"
+
+#define OFFSET(x) offsetof(NVENCContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    { "preset",   "Set the encoding preset",              OFFSET(preset),      
AV_OPT_TYPE_INT,    { .i64 = PRESET_HQ }, PRESET_DEFAULT, PRESET_LOSSLESS_HP, 
VE, "preset" },
+    { "default",    "",                                   0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_DEFAULT }, 0, 0, VE, "preset" },
+    { "hp",         "",                                   0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_HP }, 0, 0, VE, "preset" },
+    { "hq",         "",                                   0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_HQ }, 0, 0, VE, "preset" },
+    { "bd",         "",                                   0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_BD }, 0, 0, VE, "preset" },
+    { "ll",         "low latency",                        0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_LOW_LATENCY_DEFAULT }, 0, 0, VE, "preset" },
+    { "llhq",       "low latency hq",                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_LOW_LATENCY_HQ }, 0, 0, VE, "preset" },
+    { "llhp",       "low latency hp",                     0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_LOW_LATENCY_HP }, 0, 0, VE, "preset" },
+    { "lossless",   "lossless",                           0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_LOSSLESS_DEFAULT }, 0, 0, VE, "preset" },
+    { "losslesshp", "lossless hp",                        0,                   
AV_OPT_TYPE_CONST,  { .i64 = PRESET_LOSSLESS_HP }, 0, 0, VE, "preset" },
+    { "profile", "Set the encoding profile",             OFFSET(profile),      
AV_OPT_TYPE_INT,    { .i64 = FF_PROFILE_HEVC_MAIN }, FF_PROFILE_HEVC_MAIN, 
FF_PROFILE_HEVC_MAIN, VE, "profile" },
+    { "high",    "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = FF_PROFILE_HEVC_MAIN }, 0, 0, VE, "profile" },
+    { "level",   "Set the encoding level restriction",   OFFSET(level),        
AV_OPT_TYPE_INT,    { .i64 = NV_ENC_LEVEL_AUTOSELECT }, 
NV_ENC_LEVEL_AUTOSELECT, NV_ENC_LEVEL_HEVC_62, VE, "level" },
+    { "1.0",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_1 },  0, 0, VE,  "level" },
+    { "2.0",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_2 },  0, 0, VE,  "level" },
+    { "2.1",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_21 }, 0, 0, VE,  "level" },
+    { "3.0",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_3 },  0, 0, VE,  "level" },
+    { "3.1",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_31 }, 0, 0, VE,  "level" },
+    { "4.0",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_4 },  0, 0, VE,  "level" },
+    { "4.1",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_41 }, 0, 0, VE,  "level" },
+    { "5.0",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_5 },  0, 0, VE,  "level" },
+    { "5.1",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_51 }, 0, 0, VE,  "level" },
+    { "5.2",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_52 }, 0, 0, VE,  "level" },
+    { "6.0",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_6 },  0, 0, VE,  "level" },
+    { "6.1",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_61 }, 0, 0, VE,  "level" },
+    { "6.2",     "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_LEVEL_HEVC_62 }, 0, 0, VE,  "level" },
+    { "tier",    "Set the encoding tier",                OFFSET(tier),         
AV_OPT_TYPE_INT,    { .i64 = NV_ENC_TIER_HEVC_MAIN }, NV_ENC_TIER_HEVC_MAIN, 
NV_ENC_TIER_HEVC_HIGH, VE, "tier"},
+    { "main",    "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_TIER_HEVC_MAIN }, 0, 0, VE, "tier" },
+    { "high",    "",                                     0,                    
AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_TIER_HEVC_HIGH }, 0, 0, VE, "tier" },
+    { "rc",      "Override the preset rate-control",     OFFSET(rc),           
AV_OPT_TYPE_INT,    { .i64 = -1 },                   -1, 0, VE, "rc" },
+    { "constqp",          "Constant QP mode",                                  
                          0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_CONSTQP },              0, 0, VE, "rc" },
+    { "vbr",              "Variable bitrate mode",                             
                          0, AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_PARAMS_RC_VBR 
},                  0, 0, VE, "rc" },
+    { "cbr",              "Constant bitrate mode",                             
                          0, AV_OPT_TYPE_CONST,  { .i64 = NV_ENC_PARAMS_RC_CBR 
},                  0, 0, VE, "rc" },
+    { "vbr_minqp",        "Variable bitrate mode with MinQP",                  
                          0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_VBR_MINQP },            0, 0, VE, "rc" },
+    { "ll_2pass_quality", "Multi-pass optimized for image quality (only for 
low-latency presets)",       0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_2_PASS_QUALITY },       0, 0, VE, "rc" },
+    { "ll_2pass_size",    "Multi-pass optimized for constant frame size (only 
for low-latency presets)", 0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP }, 0, 0, VE, "rc" },
+    { "vbr_2pass",        "Multi-pass variable bitrate mode",                  
                          0, AV_OPT_TYPE_CONST,  { .i64 = 
NV_ENC_PARAMS_RC_2_PASS_VBR },           0, 0, VE, "rc" },
+    { "surfaces", "Number of concurrent surfaces",        OFFSET(nb_surfaces), 
AV_OPT_TYPE_INT,    { .i64 = 32 },                   0, INT_MAX, VE },
+    { "device",   "Select a specific NVENC device",       OFFSET(device),      
AV_OPT_TYPE_INT,    { .i64 = -1 },                   -2, INT_MAX, VE, "device" 
},
+    { "any",      "Pick the first device available",      0,                   
AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "device" },
+    { "list",     "List the available devices",           0,                   
AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "device" },
+    { NULL }
+};
+
+static const AVClass nvenc_hevc_class = {
+    .class_name = "nvenc_hevc",
+    .item_name = av_default_item_name,
+    .option = options,
+    .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVCodecDefault defaults[] = {
+    { "b", "0" },
+    { "qmin", "-1" },
+    { "qmax", "-1" },
+    { "qdiff", "-1" },
+    { "qblur", "-1" },
+    { "qcomp", "-1" },
+    { NULL },
+};
+
+AVCodec ff_hevc_nvenc_encoder = {
+    .name           = "nvenc_hevc",
+    .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),
+    .priv_class     = &nvenc_hevc_class,
+    .defaults       = defaults,
+    .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12,
+                                                    AV_PIX_FMT_YUV420P,
+                                                    AV_PIX_FMT_YUV444P,
+                                                    AV_PIX_FMT_NONE },
+    .capabilities   = CODEC_CAP_DELAY,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index c57bd85..6105a63 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 #include "libavutil/version.h"

 #define LIBAVCODEC_VERSION_MAJOR 56
-#define LIBAVCODEC_VERSION_MINOR 25
+#define LIBAVCODEC_VERSION_MINOR 26
 #define LIBAVCODEC_VERSION_MICRO  0

 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
--
2.3.2

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to