Merge commit 'b08caa87c35a768ec0abb16b1e99c3a85f1df28e'
authorMichael Niedermayer <michaelni@gmx.at>
Mon, 1 Jun 2015 01:13:03 +0000 (03:13 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Mon, 1 Jun 2015 01:13:55 +0000 (03:13 +0200)
* commit 'b08caa87c35a768ec0abb16b1e99c3a85f1df28e':
  nvenc: H264 and HEVC encoders

Conflicts:
Changelog
configure
libavcodec/Makefile
libavcodec/version.h

This implementation is merged under the name nvenc_b*

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
Changelog
configure
libavcodec/Makefile
libavcodec/allcodecs.c
libavcodec/nvenc_b.c
libavcodec/nvenc_b.h
libavcodec/nvenc_b_h264.c
libavcodec/nvenc_b_hevc.c
libavcodec/version.h

diff --cc Changelog
+++ b/Changelog
@@@ -2,57 -2,17 +2,58 @@@ Entries are sorted chronologically fro
  releases are sorted from youngest to oldest.
  
  version <next>:
 -- aliases and defaults for Ogg subtypes (opus, spx)
 -- HEVC/H.265 RTP payload format (draft v6) packetizer and depacketizer
 -- avplay now exits by default at the end of playback
 -- XCB-based screen-grabber
 -- creating DASH compatible fragmented MP4, MPEG-DASH segmenting muxer
 -- H.261 RTP payload format (RFC 4587) depacketizer and experimental packetizer
 +- FFT video filter
 +- TDSC decoder
 +- DTS lossless extension (XLL) decoding (not lossless, disabled by default)
 +- showwavespic filter
 +- DTS decoding through libdcadec
 +- Drop support for nvenc API before 5.0
 +- nvenc H265 encoder
 +- Detelecine filter
 +- Intel QSV-accelerated H.264 encoding
 +- MMAL-accelerated H.264 decoding
 +- basic APNG encoder and muxer with default extension "apng"
 +- unpack DivX-style packed B-frames in MPEG-4 bitstream filter
 +- WebM Live Chunk Muxer
 +- nvenc level and tier options
 +- chorus filter
 +- Canopus HQ/HQA decoder
 +- Automatically rotate videos based on metadata in ffmpeg
 +- improved Quickdraw compatibility
 +- VP9 high bit-depth and extended colorspaces decoding support
 +- WebPAnimEncoder API when available for encoding and muxing WebP
 +- Direct3D11-accelerated decoding
 +- Support Secure Transport
++- NVIDIA NVENC-accelerated H.264 and HEVC encoding support
 +
 +
 +version 2.6:
 +- nvenc encoder
 +- 10bit spp filter
 +- colorlevels filter
 +- RIFX format for *.wav files
  - RTP/mpegts muxer
 -- VP8 in Ogg demuxing
 +- non continuous cache protocol support
 +- tblend filter
 +- cropdetect support for non 8bpp, absolute (if limit >= 1) and relative (if limit < 1.0) threshold
 +- Camellia symmetric block cipher
  - OpenH264 encoder wrapper
 +- VOC seeking support
 +- Closed caption Decoder
 +- fspp, uspp, pp7 MPlayer postprocessing filters ported to native filters
 +- showpalette filter
 +- Twofish symmetric block cipher
  - Support DNx100 (960x720@8)
 -- Direct3D11-accelerated decoding
 +- eq2 filter ported from libmpcodecs as eq filter
 +- removed libmpcodecs
 +- Changed default DNxHD colour range in QuickTime .mov derivatives to mpeg range
 +- ported softpulldown filter from libmpcodecs as repeatfields filter
 +- dcshift filter
 +- RTP depacketizer for loss tolerant payload format for MP3 audio (RFC 5219)
 +- RTP depacketizer for AC3 payload format (RFC 4184)
 +- palettegen and paletteuse filters
 +- VP9 RTP payload format (draft 0) experimental depacketizer
 +- RTP depacketizer for DV (RFC 6469)
  - DXVA2-accelerated HEVC decoding
  - AAC ELD 480 decoding
  - Intel QSV-accelerated H.264 decoding
diff --cc configure
+++ b/configure
@@@ -258,29 -214,16 +258,29 @@@ External library support
    --enable-libx264         enable H.264 encoding via x264 [no]
    --enable-libx265         enable HEVC encoding via x265 [no]
    --enable-libxavs         enable AVS encoding via xavs [no]
 -  --enable-libxcb          enable X11 grabbing using XCB [no]
 -  --enable-libxcb-shm      enable X11 grabbing shm communication [auto]
 -  --enable-libxcb-xfixes   enable X11 grabbing mouse rendering [auto]
 +  --enable-libxcb          enable X11 grabbing using XCB [autodetect]
 +  --enable-libxcb-shm      enable X11 grabbing shm communication [autodetect]
 +  --enable-libxcb-xfixes   enable X11 grabbing mouse rendering [autodetect]
 +  --enable-libxcb-shape    enable X11 grabbing shape rendering [autodetect]
    --enable-libxvid         enable Xvid encoding via xvidcore,
                             native MPEG-4/Xvid encoder exists [no]
 +  --enable-libzmq          enable message passing via libzmq [no]
 +  --enable-libzvbi         enable teletext support via libzvbi [no]
 +  --disable-lzma           disable lzma [autodetect]
 +  --enable-decklink        enable Blackmagick DeckLink I/O support [no]
    --enable-mmal            enable decoding via MMAL [no]
-   --enable-nvenc           enable NVIDIA NVENC support [no]
+   --enable-nvenc           enable encoding via NVENC [no]
 -  --enable-openssl         enable openssl [no]
 +  --enable-openal          enable OpenAL 1.1 capture support [no]
 +  --enable-opencl          enable OpenCL code
 +  --enable-opengl          enable OpenGL rendering [no]
 +  --enable-openssl         enable openssl, needed for https support
 +                           if gnutls is not used [no]
 +  --disable-sdl            disable sdl [autodetect]
 +  --disable-securetransport disable Secure Transport, needed for TLS support
 +                           on OSX if openssl and gnutls are not used [autodetect]
    --enable-x11grab         enable X11 grabbing (legacy) [no]
 -  --enable-zlib            enable zlib [autodetect]
 +  --disable-xlib           disable xlib [autodetect]
 +  --disable-zlib           disable zlib [autodetect]
  
  Toolchain options:
    --arch=ARCH              select architecture [$arch]
@@@ -1769,9 -1485,8 +1769,10 @@@ SYSTEM_FUNCS=
      inet_aton
      isatty
      jack_port_get_latency_range
 +    kbhit
+     LoadLibrary
      localtime_r
 +    lzo1x_999_compress
      mach_absolute_time
      MapViewOfFile
      memalign
@@@ -2114,8 -1781,10 +2115,10 @@@ me_cmp_select="fdctdsp idctdsp pixblock
  mpeg_er_select="error_resilience"
  mpegaudio_select="mpegaudiodsp"
  mpegaudiodsp_select="dct"
 -mpegvideo_select="blockdsp hpeldsp idctdsp me_cmp videodsp"
 +mpegvideo_select="blockdsp h264chroma hpeldsp idctdsp me_cmp videodsp"
  mpegvideoenc_select="me_cmp mpegvideo pixblockdsp qpeldsp"
+ nvenc_deps_any="dlopen LoadLibrary"
+ nvenc_extralibs='$ldl'
  qsvdec_select="qsv"
  qsvenc_select="qsv"
  
@@@ -2198,8 -1860,9 +2202,9 @@@ h264_qsv_decoder_select="h264_mp4toanne
  h264_qsv_encoder_deps="libmfx"
  h264_qsv_encoder_select="qsvenc"
  hevc_decoder_select="bswapdsp cabac golomb videodsp"
 -huffyuv_decoder_select="bswapdsp huffyuvdsp"
 -huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp"
+ hevc_nvenc_encoder_deps="nvenc"
 +huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp"
 +huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llviddsp"
  iac_decoder_select="imc_decoder"
  imc_decoder_select="bswapdsp fft mdct sinewin"
  indeo3_decoder_select="hpeldsp"
@@@ -4978,8 -4196,8 +4983,9 @@@ check_func_headers windows.h CoTaskMemF
  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 PeekNamedPipe
  check_func_headers windows.h SetConsoleTextAttribute
  check_func_headers windows.h Sleep
  check_func_headers windows.h VirtualAlloc
@@@ -5172,27 -4330,6 +5178,23 @@@ enabled mmal              && { check_li
                                      check_lib interface/mmal/mmal.h mmal_port_connect ; }
                                  check_lib interface/mmal/mmal.h mmal_port_connect ; } ||
                                 die "ERROR: mmal not found"; }
- enabled nvenc             && { 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"; } &&
-                              { [ $target_os != cygwin ] || die "ERROR: NVENC is not supported on Cygwin currently."; }
 +enabled openal            && { { for al_libs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do
 +                               check_lib 'AL/al.h' alGetError "${al_libs}" && break; done } ||
 +                               die "ERROR: openal not found"; } &&
 +                             { check_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" ||
 +                               die "ERROR: openal must be installed and version must be 1.1 or compatible"; }
 +enabled opencl            && { check_lib2 OpenCL/cl.h clEnqueueNDRangeKernel -Wl,-framework,OpenCL ||
 +                               check_lib2 CL/cl.h clEnqueueNDRangeKernel -lOpenCL ||
 +                               die "ERROR: opencl not found"; } &&
 +                             { check_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" ||
 +                               check_cpp_condition "CL/cl.h" "defined(CL_VERSION_1_2)" ||
 +                               die "ERROR: opencl must be installed and version must be 1.2 or compatible"; }
 +enabled opengl            && { check_lib GL/glx.h glXGetProcAddress "-lGL" ||
 +                               check_lib2 windows.h wglGetProcAddress "-lopengl32 -lgdi32" ||
 +                               check_lib2 OpenGL/gl3.h glGetError "-Wl,-framework,OpenGL" ||
 +                               check_lib2 ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" ||
 +                               die "ERROR: opengl not found."
 +                             }
  enabled openssl           && { check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto ||
                                 check_lib openssl/ssl.h SSL_library_init -lssl32 -leay32 ||
                                 check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 ||
@@@ -5212,49 -4348,28 +5214,58 @@@ if enabled libdc1394; the
          enable libdc1394_1; } ||
      die "ERROR: No version of libdc1394 found "
  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 &&
 -    enable sdl
+ 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";
++    { [ $target_os != cygwin ] || die "ERROR: NVENC is not supported on Cygwin currently."; }
+ fi
 +if ! disabled sdl; then
 +    SDL_CONFIG="${cross_prefix}sdl-config"
 +    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 &&
 +        enable sdl
 +    else
 +        if "${SDL_CONFIG}" --version > /dev/null 2>&1; then
 +            sdl_cflags=$("${SDL_CONFIG}" --cflags)
 +            sdl_libs=$("${SDL_CONFIG}" --libs)
 +            check_func_headers SDL_version.h SDL_Linked_Version $sdl_cflags $sdl_libs &&
 +            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 &&
 +            enable sdl
 +        elif enabled sdl ; then
 +            die "ERROR: SDL not found"
 +        else
 +            disable sdl
 +        fi
 +    fi
  fi
 -
 +enabled sdl && add_cflags $sdl_cflags && add_extralibs $sdl_libs
 +
 +disabled securetransport || { check_func SecIdentityCreate "-Wl,-framework,CoreFoundation -Wl,-framework,Security" &&
 +    check_lib2 "Security/SecureTransport.h Security/Security.h" "SSLCreateContext SecItemImport" "-Wl,-framework,CoreFoundation -Wl,-framework,Security" &&
 +    enable securetransport; }
 +
 +makeinfo --version > /dev/null 2>&1 && enable makeinfo  || disable makeinfo
 +enabled makeinfo && (makeinfo --version | \
 +                     grep -q 'makeinfo (GNU texinfo) 5' > /dev/null 2>&1) \
 +    && enable makeinfo_html || disable makeinfo_html
 +disabled makeinfo_html && texi2html --help 2> /dev/null | grep -q 'init-file' && enable texi2html || disable texi2html
 +perl -v            > /dev/null 2>&1 && enable perl      || disable perl
  pod2man --help     > /dev/null 2>&1 && enable pod2man   || disable pod2man
 -texi2html -version > /dev/null 2>&1 && enable texi2html || disable texi2html
 +rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout
  
  check_header linux/fb.h
 +check_header linux/videodev.h
  check_header linux/videodev2.h
 -check_struct linux/videodev2.h "struct v4l2_frmivalenum" discrete
 +check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
  
  check_header sys/videoio.h
 +check_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
  
  check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extralibs"
  # check that WM_CAP_DRIVER_CONNECT is defined to the proper value
@@@ -92,8 -81,8 +92,9 @@@ OBJS-$(CONFIG_MPEGVIDEO)               
  OBJS-$(CONFIG_MPEGVIDEOENC)            += mpegvideo_enc.o mpeg12data.o  \
                                            motion_est.o ratecontrol.o    \
                                            mpegvideoencdsp.o
 +OBJS-$(CONFIG_NVENC)                   += nvenc_a.o
  OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
 -OBJS-${CONFIG_NVENC}                   += nvenc.o
++#OBJS-${CONFIG_NVENC}                   += nvenc_b.o
  OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
  OBJS-$(CONFIG_QSV)                     += qsv.o
  OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
@@@ -274,12 -229,13 +275,14 @@@ OBJS-$(CONFIG_H264_DECODER)            
                                            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_VDA_DECODER)        += vda_h264_dec.o
++#OBJS-$(CONFIG_H264_NVENC_ENCODER)      += nvenc_b_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_HEVC_NVENC_ENCODER)      += nvenc_b_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
Simple merge
index 0000000,0000000..c479b41
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1136 @@@
++/*
++ * NVIDIA NVENC Support
++ * Copyright (C) 2015 Luca Barbato
++ *
++ * This file is part of FFmpeg.
++ *
++ * FFmpeg 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.
++ *
++ * FFmpeg 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 FFmpeg; 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 <nvEncodeAPI.h>
++#include <string.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));
++    if (!guids)
++        return AVERROR(ENOMEM);
++
++    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.den != 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];
++        }
++    }
++
++    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)
++{
++    pkt->pts      = params->outputTimeStamp;
++    pkt->duration = params->outputDuration;
++
++    return nvenc_dequeue_timestamp(ctx->timestamps, &pkt->dts);
++}
++
++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;
++
++    ret = nvenc_set_timestamp(ctx, &params, pkt);
++    if (ret < 0)
++        return ret;
++
++    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;
++}
index 0000000,0000000..06c52e8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,135 @@@
++/*
++ * This file is part of FFmpeg.
++ *
++ * FFmpeg 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.
++ *
++ * FFmpeg 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 FFmpeg; 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"
++#include "libavutil/opt.h"
++
++#include "avcodec.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 */
index 0000000,0000000..65d7b7e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,110 @@@
++/*
++ * This file is part of FFmpeg.
++ *
++ * FFmpeg 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.
++ *
++ * FFmpeg 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 FFmpeg; 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,
++};
index 0000000,0000000..c73d752
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,108 @@@
++/*
++ * This file is part of FFmpeg.
++ *
++ * FFmpeg 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.
++ *
++ * FFmpeg 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 FFmpeg; 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,
++};
@@@ -29,8 -29,8 +29,8 @@@
  #include "libavutil/version.h"
  
  #define LIBAVCODEC_VERSION_MAJOR 56
 -#define LIBAVCODEC_VERSION_MINOR 26
 -#define LIBAVCODEC_VERSION_MICRO  0
 +#define LIBAVCODEC_VERSION_MINOR  41
- #define LIBAVCODEC_VERSION_MICRO 100
++#define LIBAVCODEC_VERSION_MICRO 101
  
  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                 LIBAVCODEC_VERSION_MINOR, \