[FFmpeg-devel] ffmpeg nvenc

Agatha Hu ahu at nvidia.com
Mon Dec 29 08:29:55 CET 2014


On 2014/12/20 16:14, Philip Langdale wrote:
>
> I found two specific problems while testing the original patch and I
> put together fixes for them, but I don't have acces to the machine with
> the diffs until the 5th of Jan (whoops) so I will send those when I can.
>
> Those are: b-frame support (using a circular array of buffers) and
> correct aspect ratio for non-square pixels.
>
> --phil
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>

Thanks. Please send it when available.

And I updated the patch, replaced the std malloc/free functions with 
ffmpeg APIs and fix code according to the review. See attachment.

Agatha Hu

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel at ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
-------------- next part --------------
?diff --git a/configure b/configure
index 3328026..1f35853 100644
--- a/configure
+++ b/configure
@@ -264,6 +264,7 @@ External library support:
   --disable-lzma           disable lzma [autodetect]
   --enable-decklink        enable Blackmagick DeckLink I/O support [no]
   --enable-nvenc           enable NVIDIA NVENC support [no]
+  --enable-libnvenc        enable NVIDIA NVENC support [no]
   --enable-openal          enable OpenAL 1.1 capture support [no]
   --enable-opencl          enable OpenCL code
   --enable-opengl          enable OpenGL rendering [no]
@@ -1402,6 +1403,7 @@ EXTERNAL_LIBRARY_LIST="
     libzvbi
     lzma
     nvenc
+    libnvenc
     openal
     opencl
     opengl
@@ -2402,6 +2404,7 @@ libutvideo_decoder_deps="libutvideo"
 libutvideo_encoder_deps="libutvideo"
 libzvbi_teletext_decoder_deps="libzvbi"
 nvenc_encoder_deps="nvenc"
+libnvenc_encoder_deps="libnvenc"
 
 # demuxers / muxers
 ac3_demuxer_select="ac3_parser"
@@ -4362,6 +4365,7 @@ die_license_disabled gpl x11grab
 die_license_disabled nonfree libaacplus
 die_license_disabled nonfree libfaac
 die_license_disabled nonfree nvenc
+enabled gpl && die_license_disabled_gpl nonfree libnvenc
 enabled gpl && die_license_disabled_gpl nonfree libfdk_aac
 enabled gpl && die_license_disabled_gpl nonfree openssl
 
@@ -4937,6 +4941,13 @@ enabled libzmq            && require_pkg_config libzmq zmq.h zmq_ctx_new
 enabled libzvbi           && require libzvbi libzvbi.h vbi_decoder_new -lzvbi
 enabled nvenc             && { check_header nvEncodeAPI.h || die "ERROR: nvEncodeAPI.h not found."; } &&
                              { [ $target_os != cygwin ] || die "ERROR: NVENC is not supported on Cygwin currently."; }
+enabled libnvenc          && { { check_header nvEncodeAPI.h || die "ERROR: nvEncodeAPI.h header not found"; } &&
+                               { check_cpp_condition nvEncodeAPI.h "NVENCAPI_VERSION == 64" ||
+                                 check_cpp_condition nvEncodeAPI.h "NVENCAPI_VERSION == 80" ||
+                                 die "ERROR: Please use NVENC 4.0 or NVENC 5.0 header"; } &&                             
+                               { { check_lib2 "windows.h" LoadLibrary; } ||
+                                 { check_lib2 "dlfcn.h" dlopen -ldl; } ||
+                                 die "ERROR: LoadLibrary/dlopen not found for avisynth"; } }
 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"; } &&
diff --git a/doc/examples/Makefile b/doc/examples/Makefile
index 07251fe..c7c8e01 100644
--- a/doc/examples/Makefile
+++ b/doc/examples/Makefile
@@ -17,6 +17,7 @@ EXAMPLES=       avio_reading                       \
                 extract_mvs                        \
                 filtering_video                    \
                 filtering_audio                    \
+				libnvenc						   \
                 metadata                           \
                 muxing                             \
                 remuxing                           \
diff --git a/doc/examples/libnvenc.c b/doc/examples/libnvenc.c
new file mode 100644
index 0000000..3e23dc1
--- /dev/null
+++ b/doc/examples/libnvenc.c
@@ -0,0 +1,204 @@
+/*
+* Simple libnvenc sample
+*
+* Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+*
+* 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, version 2.1, as published by the Free Software Foundation.
+*
+* 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, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifdef HAVE_AV_CONFIG_H
+#undef HAVE_AV_CONFIG_H
+#endif
+
+#if _WIN32
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavutil/opt.h>
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdbool.h>
+
+int main(int argc, char* argv[])
+{
+    char* inputfile   = NULL;
+    char* preset      = "default";
+    bool  zerolatency = false;
+
+    AVFormatContext *ic, *oc;
+    AVCodecContext  *dec_ctx, *enc_ctx;
+    AVStream *vst_dec, *vst_enc;
+    AVCodec *dec, *enc;
+    AVPacket dec_pkt, enc_pkt;
+    AVFrame *frame;
+    int got_frame, got_pkt;
+
+    int ret;
+    int video_stream_idx; 
+    const char* filename = "out.mp4";
+
+    double bitrate;
+    int i;
+
+    for(i = 1; i < argc; i++) {
+        if(strcmp(argv[i], "-input") == 0) {
+            inputfile = argv[++i];
+        }
+        else if(strcmp(argv[i], "-preset") == 0) {  
+            preset = argv[++i];
+        }
+        else if(strcmp(argv[i], "-zerolatency") == 0) {
+            zerolatency = true;
+        }
+    }
+
+    if(inputfile == NULL) {
+        printf("Usage: libnvenc_sample -input your.input -preset [default]/slow/fast\n");
+        return 0;
+    }
+
+    //ffmpeg decoder
+    av_register_all();
+
+    //init decode context 
+	ic = NULL;
+    if(avformat_open_input(&ic, inputfile, NULL, NULL) < 0)
+    {
+        printf("can't open the file %s\n", inputfile);
+        return -1;
+    }
+
+    if(avformat_find_stream_info(ic, NULL)<0)
+    {
+        printf("can't find suitable codec parameters\n");
+        return -1;
+    }
+
+    video_stream_idx = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
+    if (video_stream_idx < 0) {
+        printf("Could not find video stream in input file!\n");
+        return -1;
+    } 
+    else {
+        vst_dec = ic->streams[video_stream_idx];
+        dec_ctx = vst_dec->codec;
+        dec = avcodec_find_decoder(dec_ctx->codec_id);
+
+        if (!dec) {
+            fprintf(stderr, "Failed to find %s codec\n",
+                av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
+            return -1;
+        }
+
+        if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
+            fprintf(stderr, "Failed to open %s codec\n",
+                av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
+            return -1;
+        }
+    }
+
+    // encode context          
+    avformat_alloc_output_context2(&oc, NULL, NULL, filename); 
+    if (!oc) {
+        printf("FFMPEG: avformat_alloc_context error\n");
+        return -1;
+    }
+
+    if ((ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE)) < 0) {
+        fprintf(stderr, "Could not open '%s'\n", filename);
+        return -1;
+    }  
+
+    enc = avcodec_find_encoder_by_name("libnvenc");
+    if(!enc) {
+        printf("Could not find libnvenc\n");
+        printf("Please run ./configure --enable-libnvenc and make ffmpeg again\n");
+        return -1;
+    }
+    vst_enc = avformat_new_stream(oc, enc);
+    if (!vst_enc) {
+        printf("FFMPEG: Could not alloc video stream");
+        return -1;
+    }
+
+    enc_ctx = vst_enc->codec;
+
+    bitrate = (double)5000000 * (dec_ctx->width * dec_ctx->height) / (1280*720);       
+    enc_ctx->codec_id       = enc->id;
+    enc_ctx->codec_type       = AVMEDIA_TYPE_VIDEO;
+    enc_ctx->width           = dec_ctx->width;
+    enc_ctx->height        = dec_ctx->height;
+    enc_ctx->pix_fmt       = dec_ctx->pix_fmt;
+    enc_ctx->time_base.num = dec_ctx->time_base.num;
+    enc_ctx->time_base.den = dec_ctx->time_base.den/2;           
+    enc_ctx->bit_rate       = bitrate;                
+    enc_ctx->flags        |= (oc->oformat->flags & AVFMT_GLOBALHEADER) ? CODEC_FLAG_GLOBAL_HEADER : 0;
+    av_opt_set(enc_ctx->priv_data, "preset", preset, 0);  // "fast" = HP, "slow" = HQ, default = LOW_LATENCY_DEFAULT
+    if(zerolatency) {
+        //use LOW_LATENCY preset
+        av_opt_set(enc_ctx->priv_data, "tune", "zerolatency", 0);
+    }
+
+    ret = avcodec_open2(enc_ctx, enc, NULL);
+    if (ret < 0) {
+        printf("could not open codec\n");
+        return -1;
+    }
+    ret = avformat_write_header(oc, NULL);      
+    
+    av_init_packet(&dec_pkt);
+    dec_pkt.data = NULL;
+    dec_pkt.size = 0;
+
+    frame = avcodec_alloc_frame();
+    got_frame = 0;
+    while(av_read_frame(ic, &dec_pkt) >= 0) {  
+        if(dec_pkt.stream_index == video_stream_idx) {
+            if(avcodec_decode_video2(dec_ctx, frame, &got_frame, &dec_pkt) < 0) {
+                printf("Error decoding frames!\n");
+                return -1;
+            }
+            if(got_frame) {
+                av_init_packet(&enc_pkt);
+                enc_pkt.data = NULL;
+                enc_pkt.size = 0;       
+                if(avcodec_encode_video2(vst_enc->codec, &enc_pkt, frame, &got_pkt) < 0) {
+                    printf("Error encoding frames!\n");
+                    return -1;
+                }
+
+                if(got_pkt) {
+                    av_write_frame(oc, &enc_pkt);
+                }
+
+                av_free_packet(&enc_pkt);  
+            }
+        }
+        av_free_packet(&dec_pkt);             
+    }
+    avcodec_free_frame(&frame);
+    av_write_trailer(oc);
+
+    avcodec_close(dec_ctx);
+    avcodec_close(enc_ctx);
+    avformat_close_input(&ic);
+
+    return 0; 
+}
diff --git a/ffmpeg.c b/ffmpeg.c
index 9f29eac..db47199 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -2839,7 +2839,7 @@ static int transcode_init(void)
                     ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option
                     av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) :
                     ost->filter->filter->inputs[0]->sample_aspect_ratio;
-                if (!strncmp(ost->enc->name, "libx264", 7) &&
+				if ((!strncmp(ost->enc->name, "libx264", 7) || !strncmp(ost->enc->name, "libnvenc", 8)) &&
                     enc_ctx->pix_fmt == AV_PIX_FMT_NONE &&
                     ost->filter->filter->inputs[0]->format != AV_PIX_FMT_YUV420P)
                     av_log(NULL, AV_LOG_WARNING,
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 8a33513..8fadeb7 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -348,6 +348,7 @@ OBJS-$(CONFIG_NELLYMOSER_DECODER)      += nellymoserdec.o nellymoser.o
 OBJS-$(CONFIG_NELLYMOSER_ENCODER)      += nellymoserenc.o nellymoser.o
 OBJS-$(CONFIG_NUV_DECODER)             += nuv.o rtjpeg.o
 OBJS-$(CONFIG_NVENC_ENCODER)           += nvenc.o
+OBJS-$(CONFIG_LIBNVENC_ENCODER)        += libnvenc.o nvencoder.o nvencoder_utils.o
 OBJS-$(CONFIG_ON2AVC_DECODER)          += on2avc.o on2avcdata.o
 OBJS-$(CONFIG_OPUS_DECODER)            += opusdec.o opus.o opus_celt.o \
                                           opus_imdct.o opus_silk.o     \
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 8ceee2f..b0ff8b4 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -224,6 +224,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(MXPEG,             mxpeg);
     REGISTER_DECODER(NUV,               nuv);
     REGISTER_ENCODER(NVENC,             nvenc);
+	REGISTER_ENCODER(LIBNVENC,			libnvenc);
     REGISTER_DECODER(PAF_VIDEO,         paf_video);
     REGISTER_ENCDEC (PAM,               pam);
     REGISTER_ENCDEC (PBM,               pbm);
diff --git a/libavcodec/libnvenc.c b/libavcodec/libnvenc.c
new file mode 100644
index 0000000..de8750c
--- /dev/null
+++ b/libavcodec/libnvenc.c
@@ -0,0 +1,413 @@
+/*
+* H.264 encoding using NVENC library
+*
+* Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+*
+* 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, version 2.1, as published by the Free Software Foundation.
+*
+* 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "libnvenc.h"
+#include <float.h>
+
+// ffmpeg-x264 param-to-string macros
+#define OPT_STRSTR(x, y)\
+    if (y)\
+    {\
+        x264_argv[x264_argc++] = av_strdup(x);  \
+        x264_argv[x264_argc++] = av_strdup(y);  \
+    }
+#define OPT_NUMSTR(x, y)\
+    if (y > 0)\
+    {\
+        x264_argv[x264_argc++] = av_strdup(x);               \
+        x264_argv[x264_argc] = av_malloc(sizeof(char) * 32); \
+        snprintf(x264_argv[x264_argc++], 32, "%u", y);            \
+    }
+#define OPT_BOOLSTR(x, y)\
+    if (y)\
+    {\
+        x264_argv[x264_argc++] = av_strdup(x);  \
+        x264_argv[x264_argc++] = av_strdup("1");\
+    }
+
+typedef struct NvEncContext {
+    const AVClass  *class;
+
+    nvenc_t        *nvenc;          // NVENC encoder instance
+    nvenc_cfg_t     nvenc_cfg;      // NVENC encoder config
+
+    char           *x264_opts;      // List of x264 options in opt:arg or opt=arg format
+    char           *x264_params;    // List of x264 options in opt:arg or opt=arg format
+
+    char           *preset;
+    char           *tune;
+    char           *profile;
+    char           *level;
+    int             fastfirstpass;
+    char           *wpredp;
+    float           crf;
+    float           crf_max;
+    int             cqp;
+    int             aq_mode;
+    float           aq_strength;
+    char           *psy_rd;
+    int             psy;
+    int             rc_lookahead;
+    int             weightp;
+    int             weightb;
+    int             ssim;
+    int             intra_refresh;
+    int             bluray_compat;
+    int             b_bias;
+    int             b_pyramid;
+    int             mixed_refs;
+    int             dct8x8;
+    int             fast_pskip;
+    int             aud;
+    int             mbtree;
+    char           *deblock;
+    float           cplxblur;
+    char           *partitions;
+    int             direct_pred;
+    int             slice_max_size;
+    char           *stats;
+    int             nal_hrd;
+} NvEncContext;
+
+static const enum AVPixelFormat nvenc_pix_fmts[] = {
+    AV_PIX_FMT_NV12,
+    AV_PIX_FMT_YUV420P,
+    AV_PIX_FMT_YUVJ420P,
+    AV_PIX_FMT_NONE
+};
+static int map_avpixfmt_bufferformat(enum AVPixelFormat pix_fmt)
+{
+    switch (pix_fmt) {
+    case AV_PIX_FMT_YUV420P:
+    case AV_PIX_FMT_YUVJ420P:
+        return NVENC_FMT_YV12;
+    case AV_PIX_FMT_NV12:
+        return NVENC_FMT_NV12;
+    default:
+        return 0;
+    }
+}
+static int map_avpixfmt_numplanes(enum AVPixelFormat pix_fmt)
+{
+    switch (pix_fmt) {
+    case AV_PIX_FMT_YUV420P:
+    case AV_PIX_FMT_YUVJ420P:
+        return 3;
+    case AV_PIX_FMT_NV12:
+        return 2;
+    default:
+        return 3;
+    }
+}
+
+static av_cold int ff_libnvenc_init(AVCodecContext *avctx)
+{
+    NvEncContext *nvenc_ctx = (NvEncContext*)avctx->priv_data;
+    int x264_argc;
+    char **x264_argv;
+
+    // Basic
+    nvenc_ctx->nvenc_cfg.width        = avctx->width;
+    nvenc_ctx->nvenc_cfg.height       = avctx->height;
+    nvenc_ctx->nvenc_cfg.frameRateNum = avctx->time_base.den;
+    nvenc_ctx->nvenc_cfg.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
+
+    // Codec
+    if (avctx->profile >= 0)
+        nvenc_ctx->nvenc_cfg.profile      = avctx->profile;
+    if (avctx->gop_size >= 0)
+        nvenc_ctx->nvenc_cfg.gopLength    = avctx->gop_size;
+    else if (!(avctx->flags & CODEC_FLAG_CLOSED_GOP))
+        nvenc_ctx->nvenc_cfg.gopLength    = UINT_MAX;   // infinite GOP
+    if (avctx->max_b_frames >= 0)
+        nvenc_ctx->nvenc_cfg.numBFrames   = avctx->max_b_frames;
+    if (avctx->refs >= 0)
+        nvenc_ctx->nvenc_cfg.numRefFrames = avctx->refs;
+    if (avctx->flags & CODEC_FLAG_INTERLACED_DCT)
+        nvenc_ctx->nvenc_cfg.fieldMode    = 2;
+
+    // Rate-control
+    if (avctx->bit_rate > 0) {
+        nvenc_ctx->nvenc_cfg.rateControl   = 2;
+        nvenc_ctx->nvenc_cfg.avgBitRate    = avctx->bit_rate;
+    }
+    if (avctx->rc_max_rate >= 0) {
+        nvenc_ctx->nvenc_cfg.rateControl   = 1;
+        nvenc_ctx->nvenc_cfg.peakBitRate   = avctx->rc_max_rate;
+    }
+    if (avctx->qmin >= 0)
+        nvenc_ctx->nvenc_cfg.qpMin         = avctx->qmin;
+    if (avctx->qmax >= 0)
+        nvenc_ctx->nvenc_cfg.qpMax         = avctx->qmax;
+    if (avctx->rc_buffer_size > 0) {
+        nvenc_ctx->nvenc_cfg.vbvBufferSize = avctx->rc_buffer_size;
+        if (avctx->rc_initial_buffer_occupancy >= 0) {
+            nvenc_ctx->nvenc_cfg.vbvInitialDelay =
+                avctx->rc_initial_buffer_occupancy / avctx->rc_buffer_size;
+        }
+    }
+
+    // Codec-specific
+    if (avctx->level >= 0)
+        nvenc_ctx->nvenc_cfg.level     = avctx->level;
+    if (avctx->gop_size >= 0)
+        nvenc_ctx->nvenc_cfg.idrPeriod = avctx->gop_size;
+    if (avctx->slices > 0) {
+        nvenc_ctx->nvenc_cfg.sliceMode = 3;
+        nvenc_ctx->nvenc_cfg.sliceModeData = avctx->slices;
+    }
+    else if (avctx->rtp_payload_size > 0) {
+        nvenc_ctx->nvenc_cfg.sliceMode = 1;
+        nvenc_ctx->nvenc_cfg.sliceModeData = avctx->rtp_payload_size;
+    }
+    if (avctx->coder_type == FF_CODER_TYPE_AC)
+        nvenc_ctx->nvenc_cfg.enableCABAC = 1;
+		
+	nvenc_ctx->nvenc_cfg.enableRepeatSPSPPS = 1;
+    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER)
+        nvenc_ctx->nvenc_cfg.enableRepeatSPSPPS = 0;
+
+    // Allocate list of x264 options
+    x264_argc = 0;
+    x264_argv = av_calloc(255, sizeof(char*));
+    if (!x264_argv)
+        return AVERROR(ENOMEM);
+
+    // ffmpeg-x264 parameters
+    OPT_STRSTR("preset", nvenc_ctx->preset);
+    OPT_STRSTR("tune", nvenc_ctx->tune);
+    OPT_STRSTR("profile", nvenc_ctx->profile);
+    OPT_STRSTR("level", nvenc_ctx->level);
+    OPT_NUMSTR("qp", nvenc_ctx->cqp);
+    OPT_NUMSTR("intra-refresh", nvenc_ctx->intra_refresh);
+    OPT_NUMSTR("aud", nvenc_ctx->aud);
+    OPT_STRSTR("deblock", nvenc_ctx->deblock);
+    OPT_NUMSTR("direct-pred", nvenc_ctx->direct_pred);
+    OPT_NUMSTR("nal_hrd", nvenc_ctx->nal_hrd);
+    OPT_NUMSTR("8x8dct", nvenc_ctx->dct8x8);
+
+    // x264-style extra parameters
+    if (nvenc_ctx->x264_params) {
+        AVDictionary *param_dict = NULL;
+        AVDictionaryEntry *param_entry = NULL;
+
+        if (!av_dict_parse_string(&param_dict, nvenc_ctx->x264_params, "=", ":", 0)) {
+            while ((param_entry = av_dict_get(param_dict, "", param_entry, AV_DICT_IGNORE_SUFFIX))) {
+                x264_argv[x264_argc++] = av_strdup(param_entry->key);
+                x264_argv[x264_argc++] = av_strdup(param_entry->value);
+            }
+            av_dict_free(&param_dict);
+        }
+    }
+    // x264-style extra options
+    if (nvenc_ctx->x264_opts) {
+        AVDictionary *param_dict = NULL;
+        AVDictionaryEntry *param_entry = NULL;
+
+        if (!av_dict_parse_string(&param_dict, nvenc_ctx->x264_opts, "=", ":", 0)) {
+            while ((param_entry = av_dict_get(param_dict, "", param_entry, AV_DICT_IGNORE_SUFFIX))) {
+                x264_argv[x264_argc++] = av_strdup(param_entry->key);
+                x264_argv[x264_argc++] = av_strdup(param_entry->value);
+            }
+            av_dict_free(&param_dict);
+        }
+    }
+
+    // Notify encoder to use the list of x264 options
+    nvenc_ctx->nvenc_cfg.x264_paramc = x264_argc;
+    nvenc_ctx->nvenc_cfg.x264_paramv = x264_argv;
+
+    // Create and initialize nvencoder
+    nvenc_ctx->nvenc = nvenc_open(&nvenc_ctx->nvenc_cfg);
+    if (!nvenc_ctx->nvenc)
+		return AVERROR_EXTERNAL;
+
+    avctx->coded_frame = av_frame_alloc();
+    if (!avctx->coded_frame)
+        return AVERROR(ENOMEM);
+
+    avctx->has_b_frames = (nvenc_ctx->nvenc_cfg.numBFrames > 0) ? 1 : 0;
+    if (avctx->max_b_frames < 0)
+        avctx->max_b_frames = 0;
+    avctx->bit_rate = nvenc_ctx->nvenc_cfg.avgBitRate;
+
+    return 0;
+}
+
+static int ff_libnvenc_encode(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet)
+{
+    NvEncContext *nvenc_ctx = (NvEncContext*)avctx->priv_data;
+
+    int ret, i, user_packet = !!pkt->data;
+    nvenc_frame_t nvenc_frame;
+    nvenc_bitstream_t nvenc_bitstream;
+
+    // Check for sudden change in parameters
+    if ((avctx->width != nvenc_ctx->nvenc_cfg.width) ||
+        (avctx->height != nvenc_ctx->nvenc_cfg.height)) {
+        ret = nvenc_reconfig(nvenc_ctx->nvenc, &nvenc_ctx->nvenc_cfg);
+        if (ret < 0)
+			return AVERROR_EXTERNAL;
+    }
+
+    // Setup input
+    memset(&nvenc_frame, 0, sizeof(nvenc_frame));
+    if (frame) {
+        for (i = 0; i < map_avpixfmt_numplanes(avctx->pix_fmt); i++) {
+            nvenc_frame.planes[i] = frame->data[i];
+            nvenc_frame.stride[i] = frame->linesize[i];
+        }
+        nvenc_frame.width  = avctx->width;
+        nvenc_frame.height = avctx->height;
+        nvenc_frame.format = map_avpixfmt_bufferformat(avctx->pix_fmt);
+    }
+
+    // Setup output
+    ret = ff_alloc_packet2(avctx, pkt, nvenc_frame.width * nvenc_frame.height);
+    if (ret < 0)
+        return AVERROR(-1);
+    memset(&nvenc_bitstream, 0, sizeof(nvenc_bitstream));
+    nvenc_bitstream.payload      = pkt->data;
+    nvenc_bitstream.payload_size = pkt->size;
+
+    // Encode the picture
+    ret = nvenc_encode(nvenc_ctx->nvenc, &nvenc_frame, &nvenc_bitstream);
+
+    if (ret < 0) {
+        // Encoding failed
+        if (!user_packet)
+            av_free_packet(pkt);
+		return AVERROR(-1);
+    } else if (ret > 0) {
+        // Encoding needs more input to produce output
+        pkt->size = 0;
+        *got_packet = 0;
+        return 0;
+    } else {
+        // Encoding succeeded
+        pkt->size   = nvenc_bitstream.payload_size;
+        pkt->flags |= nvenc_bitstream.pic_type == NV_ENC_PIC_TYPE_IDR ? AV_PKT_FLAG_KEY : 0;
+
+        avctx->coded_frame->pict_type =
+            nvenc_bitstream.pic_type == NV_ENC_PIC_TYPE_P ? AV_PICTURE_TYPE_P :
+            nvenc_bitstream.pic_type == NV_ENC_PIC_TYPE_B ? AV_PICTURE_TYPE_B : AV_PICTURE_TYPE_I;
+        avctx->coded_frame->key_frame =
+            nvenc_bitstream.pic_type == NV_ENC_PIC_TYPE_IDR ? 1 : 0;
+
+        *got_packet = 1;
+    }
+
+    return 0;
+}
+
+static av_cold int ff_libnvenc_close(AVCodecContext *avctx)
+{
+    NvEncContext *nvenc_ctx = (NvEncContext*)avctx->priv_data;
+    int i;
+
+    av_freep(&avctx->extradata);
+
+    for (i = 0; i < nvenc_ctx->nvenc_cfg.x264_paramc; i++)
+        av_freep(&nvenc_ctx->nvenc_cfg.x264_paramv[i]);
+    av_freep(&nvenc_ctx->nvenc_cfg.x264_paramv);
+
+    // Destroy nvencoder
+    if (nvenc_ctx->nvenc)
+        nvenc_close(nvenc_ctx->nvenc);
+
+    av_frame_free(&avctx->coded_frame);
+
+    return 0;
+}
+
+
+// Options
+#define OFFSET(x)   offsetof(NvEncContext, x)
+#define OPTIONS     AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    { "preset"         , "Set x264 encoding preset"       , OFFSET(preset)          , AV_OPT_TYPE_STRING, { .str = "medium" }   , 0, 0, OPTIONS},
+    { "tune"           , "Set x264 encoding tuning"       , OFFSET(tune)            , AV_OPT_TYPE_STRING, { 0 }                 , 0, 0, OPTIONS},
+    { "profile"        , "Set H.264 profile restrictions.", OFFSET(profile)         , AV_OPT_TYPE_STRING, { 0 }                 , 0, 0, OPTIONS},
+    { "fastfirstpass"  , "Ignored."                       , OFFSET(fastfirstpass)   , AV_OPT_TYPE_INT   , { .i64 = 1 }          , 0, 1, OPTIONS},
+    { "level"          , "Set H.264 level"                , OFFSET(level)           , AV_OPT_TYPE_STRING, { .str=NULL}          , 0, 0, OPTIONS},
+    { "passlogfile"    , "Ignored."                       , OFFSET(stats)           , AV_OPT_TYPE_STRING, { .str=NULL}          , 0, 0, OPTIONS},
+    { "wpredp"         , "Ignored."                       , OFFSET(wpredp)          , AV_OPT_TYPE_STRING, { .str=NULL}          , 0, 0, OPTIONS},
+    { "crf"            , "Ignored."                       , OFFSET(crf)             , AV_OPT_TYPE_FLOAT , { .dbl = -1 }         , -1, FLT_MAX, OPTIONS },
+    { "crf_max"        , "Ignored."                       , OFFSET(crf_max)         , AV_OPT_TYPE_FLOAT , { .dbl = -1 }         , -1, FLT_MAX, OPTIONS },
+    { "qp"             , "Constant quantization parameter", OFFSET(cqp)             , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, INT_MAX, OPTIONS },
+    { "aq-mode"        , "Ignored."                       , OFFSET(aq_mode)         , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, INT_MAX, OPTIONS, "aq_mode"},
+    { "aq-strength"    , "Ignored."                       , OFFSET(aq_strength)     , AV_OPT_TYPE_FLOAT , {.dbl = -1}           , -1, FLT_MAX, OPTIONS},
+    { "psy"            , "Ignored."                       , OFFSET(psy)             , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS },
+    { "psy-rd"         , "Ignored."                       , OFFSET(psy_rd)          , AV_OPT_TYPE_STRING, { 0 }                 , 0, 0, OPTIONS},
+    { "rc-lookahead"   , "Ignored."                       , OFFSET(rc_lookahead)    , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, INT_MAX, OPTIONS },
+    { "weightb"        , "Ignored."                       , OFFSET(weightb)         , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS },
+    { "weightp"        , "Ignored."                       , OFFSET(weightp)         , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, INT_MAX, OPTIONS, "weightp" },
+    { "ssim"           , "Ignored."                       , OFFSET(ssim)            , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS },
+    { "intra-refresh"  , "Use Periodic Intra Refresh."    , OFFSET(intra_refresh)   , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS },
+    { "bluray-compat"  , "Ignored."                       , OFFSET(bluray_compat)   , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS },
+    { "b-bias"         , "Ignored."                       , OFFSET(b_bias)          , AV_OPT_TYPE_INT   , { .i64 = INT_MIN}     , INT_MIN, INT_MAX, OPTIONS },
+    { "b-pyramid"      , "Ignored."                       , OFFSET(b_pyramid)       , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, INT_MAX, OPTIONS, "b_pyramid" },
+    { "mixed-refs"     , "Ignored."                       , OFFSET(mixed_refs)      , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS },
+    { "8x8dct"         , "High profile 8x8 transform."    , OFFSET(dct8x8)          , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS},
+    { "fast-pskip"     , "Ignored."                       , OFFSET(fast_pskip)      , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS},
+    { "aud"            , "Insert access unit delimiters." , OFFSET(aud)             , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS},
+    { "mbtree"         , "Ignored."                       , OFFSET(mbtree)          , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, 1, OPTIONS},
+    { "deblock"        , "Loop filter, in <alpha:beta>."  , OFFSET(deblock)         , AV_OPT_TYPE_STRING, { 0 },  0, 0          , OPTIONS},
+    { "cplxblur"       , "Ignored."                       , OFFSET(cplxblur)        , AV_OPT_TYPE_FLOAT , { .dbl = -1 }         , -1, FLT_MAX, OPTIONS},
+    { "partitions"     , "Ignored."                       , OFFSET(partitions)      , AV_OPT_TYPE_STRING, { 0 }, 0, 0           , OPTIONS},
+    { "direct-pred"    , "Direct MV prediction mode"      , OFFSET(direct_pred)     , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, INT_MAX, OPTIONS, "direct-pred" },
+    { "slice-max-size" , "Ignored."                       , OFFSET(slice_max_size)  , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, INT_MAX, OPTIONS },
+    { "stats"          , "Ignored."                       , OFFSET(stats)           , AV_OPT_TYPE_STRING, { 0 }                 ,  0,       0, OPTIONS },
+    { "nal-hrd"        , "Insert HRD info NALUs"          , OFFSET(nal_hrd)         , AV_OPT_TYPE_INT   , { .i64 = -1 }         , -1, INT_MAX, OPTIONS, "nal-hrd" },
+    { "x264opts"       , "Apply x264-style options using a :-separated list of key=value pairs", OFFSET(x264_opts)              , AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, OPTIONS},
+    { "x264-params"    , "Apply x264-style options using a :-separated list of key=value pairs", OFFSET(x264_params)            , AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, OPTIONS },
+    { NULL }           ,
+};
+static const AVCodecDefault nvenc_defaults[] = {
+    { "qmin" , "-1"    },
+    { "qmax" , "-1"    },
+    { "refs" , "-1"    },
+    { "flags", "+cgop" },
+    { NULL },
+};
+static const AVClass nvenc_class = {
+    .class_name = "NVIDIA NVENC",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_libnvenc_encoder = {
+    .name             = "libnvenc",
+    .long_name        = NULL_IF_CONFIG_SMALL("libnvenc H.264 / MPEG-4 AVC"),
+    .type             = AVMEDIA_TYPE_VIDEO,
+    .id               = AV_CODEC_ID_H264,
+    .priv_data_size   = sizeof(NvEncContext),
+    .capabilities     = 0,
+    .pix_fmts         = nvenc_pix_fmts,
+    .priv_class       = &nvenc_class,
+    .defaults         = nvenc_defaults,
+    .init             = ff_libnvenc_init,
+    .encode2          = ff_libnvenc_encode,
+    .close            = ff_libnvenc_close,
+};
diff --git a/libavcodec/libnvenc.h b/libavcodec/libnvenc.h
new file mode 100644
index 0000000..42718a2
--- /dev/null
+++ b/libavcodec/libnvenc.h
@@ -0,0 +1,142 @@
+/*
+* NVENC wrapper header
+*
+* Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+*
+* 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, version 2.1, as published by the Free Software Foundation.
+*
+* 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NVENC_H
+#define _NVENC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "nvEncodeAPI.h"
+
+/**
+ * List of supported pixel formats
+ */
+enum nvenc_pixfmt_t
+{
+    NVENC_FMT_NV12,
+    NVENC_FMT_YV12,
+};
+
+/**
+ * Handle to an encode session
+ */
+typedef struct nvenc_t nvenc_t;
+
+/**
+ * Initialization parameters for an encode session
+ */
+typedef struct nvenc_cfg_t
+{
+    // Basic
+    uint32_t            width;
+    uint32_t            height;
+    uint32_t            frameRateNum;
+    uint32_t            frameRateDen;
+
+    // Codec
+    uint32_t            profile;
+    uint32_t            gopLength;
+    uint32_t            numBFrames;
+    uint32_t            numRefFrames;
+    uint32_t            fieldMode;
+
+    // Rate-control
+    uint32_t            rateControl;
+    uint32_t            avgBitRate;
+    uint32_t            peakBitRate;
+    uint32_t            qpI;
+    uint32_t            qpP;
+    uint32_t            qpB;
+    uint32_t            qpMin;
+    uint32_t            qpMax;
+    uint32_t            vbvBufferSize;
+    uint32_t            vbvInitialDelay;
+
+    // H.264
+    uint32_t            level;
+    uint32_t            idrPeriod;
+    bool                enableCABAC;
+    bool                disableSPSPPS;
+    bool                enableRepeatSPSPPS;
+    bool                enableFMO;
+    bool                enableAUD;
+    bool                enableSEIBufferPeriod;
+    bool                enableSEIPictureTime;
+    bool                enableSEIUser;
+    bool                enableVUI;
+    uint32_t            intraRefreshCount;
+    uint32_t            intraRefreshPeriod;
+    uint32_t            bdirectMode;
+    uint32_t            adaptiveTransformMode;
+    uint32_t            sliceMode;
+    uint32_t            sliceModeData;
+    uint32_t            disableDeblockingFilterIDC;
+
+    // x264-style list of options
+    char              **x264_paramv;
+    uint32_t            x264_paramc;
+} nvenc_cfg_t;
+
+/**
+ * Configuration parameters for encoding a frame
+ */
+typedef struct nvenc_frame_t
+{
+    uint8_t            *planes[3];
+    uint32_t            stride[3];
+
+    uint32_t            width;
+    uint32_t            height;
+    enum nvenc_pixfmt_t format;
+    uint32_t            frame_idx;
+    uint32_t            frame_type;
+    bool                force_idr;
+    bool                force_intra;
+} nvenc_frame_t;
+
+/**
+ * Encoded output bitstream data
+ */
+typedef struct nvenc_bitstream_t
+{
+    uint8_t            *payload;
+    size_t              payload_size;
+
+    uint32_t            pic_idx;
+    NV_ENC_PIC_TYPE pic_type;
+} nvenc_bitstream_t;
+
+/**
+ * Bitstream header data
+ */
+typedef struct nvenc_header_t
+{
+    uint8_t            *payload;
+    size_t              payload_size;
+} nvenc_header_t;
+
+nvenc_t*                nvenc_open(nvenc_cfg_t *nvenc_cfg);
+int                     nvenc_encode(nvenc_t *nvenc, nvenc_frame_t *nvenc_frame, nvenc_bitstream_t *nvenc_bitstream);
+void                    nvenc_close(nvenc_t *nvenc);
+int                     nvenc_reconfig(nvenc_t *nvenc, nvenc_cfg_t *nvenc_cfg);
+int                     nvenc_header(nvenc_t *nvenc, nvenc_header_t *nvenc_header);
+
+#endif // _NVENC_H
diff --git a/libavcodec/nvencoder.c b/libavcodec/nvencoder.c
new file mode 100644
index 0000000..04bf59c
--- /dev/null
+++ b/libavcodec/nvencoder.c
@@ -0,0 +1,854 @@
+/*
+* NVENC wrapper implementation
+*
+* Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+*
+* 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, version 2.1, as published by the Free Software Foundation.
+*
+* 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libnvenc.h"
+#include "nvencoder.h"
+#include "nvencoder_utils.h"
+#include <stdlib.h>
+#include <libavutil/avutil.h>
+
+// Definitions
+#if defined (_WIN32)
+#define NVCUDA_LIB      TEXT("nvcuda.dll")
+#if defined (_WIN64)
+#define NVENCODEAPI_LIB TEXT("nvEncodeAPI64.dll")
+#else
+#define NVENCODEAPI_LIB TEXT("nvEncodeAPI.dll")
+#endif
+
+#else
+#include <string.h>     // for memset
+#include <dlfcn.h>
+#define NVCUDA_LIB      "libcuda.so"
+#define NVENCODEAPI_LIB "libnvidia-encode.so"
+#define LoadLibrary(x)  dlopen(x, RTLD_NOW | RTLD_GLOBAL)
+#define GetProcAddress  dlsym
+#define FreeLibrary     dlclose
+#endif
+
+// Typedefs
+#if defined (NV_CUDACTX)
+typedef CUresult    (CUDAAPI  *cuinit_t)(unsigned int);
+typedef CUresult    (CUDAAPI  *cudeviceget_t)(CUdevice*, int);
+typedef CUresult    (CUDAAPI  *cudevicecomputecapability_t)(int*, int*, CUdevice);
+typedef CUresult    (CUDAAPI  *cuctxcreate_t)(CUcontext*, unsigned int, CUdevice);
+typedef CUresult    (CUDAAPI  *cuctxdestroy_t)(CUcontext);
+#endif
+#if defined (NV_D3DCTX)
+typedef IDirect3D9* (WINAPI   *directd3dcreate9_t)(UINT);
+#endif
+typedef NVENCSTATUS (NVENCAPI *nvencodeapicreateinstance_t)(NV_ENCODE_API_FUNCTION_LIST*);
+
+// Static data
+static const GUID NV_ENC_CODEC_NULL_GUID =
+{ 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
+
+// Map numeric parameters to NVENCODEAPI definitions
+static GUID map_profile(uint32_t profile)
+{
+    switch (profile)
+    {
+    case 66:
+        return NV_ENC_H264_PROFILE_BASELINE_GUID;
+    case 77:
+        return NV_ENC_H264_PROFILE_MAIN_GUID;
+    case 100:
+        return NV_ENC_H264_PROFILE_HIGH_GUID;
+    default:
+        return NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID;
+    }
+}
+static NV_ENC_LEVEL map_level(uint32_t level)
+{
+    return (NV_ENC_LEVEL)(level);
+}
+
+
+static void deinit_device(nvencoder_t *nvenc)
+{
+#if defined (NV_CUDACTX)
+    cuctxdestroy_t cuctxdestroy;
+
+    if (nvenc->device.type == NV_ENC_DEVICE_TYPE_CUDA)
+    {
+        if (nvenc->device.cudacontext)
+        {
+            cuctxdestroy =
+                (cuctxdestroy_t)GetProcAddress(nvenc->device.lib, "cuCtxDestroy");
+            if (cuctxdestroy)
+                cuctxdestroy((CUcontext)nvenc->device.cudacontext);
+            nvenc->device.cudacontext = NULL;
+        }
+        if (nvenc->device.cudadevice)
+        {
+            nvenc->device.cudadevice = 0;
+        }
+        if (nvenc->device.lib)
+        {
+            FreeLibrary(nvenc->device.lib);
+            nvenc->device.lib = NULL;
+        }
+    }
+#endif // NV_CUDACTX
+#if defined (NV_D3DCTX)
+    if (nvenc->device.type == NV_ENC_DEVICE_TYPE_DIRECTX)
+    {
+        if (nvenc->device.d3ddevice)
+        {
+            IDirect3DDevice9_Release((IDirect3DDevice9*)nvenc->device.d3ddevice);
+            nvenc->device.d3ddevice = NULL;
+        }
+        if (nvenc->device.d3d)
+        {
+            IDirect3D9_Release(nvenc->device.d3d);
+            nvenc->device.d3d = NULL;
+        }
+        if (nvenc->device.lib)
+        {
+            FreeLibrary(nvenc->device.lib);
+            nvenc->device.lib = NULL;
+        }
+    }
+#endif // NV_D3DCTX
+
+    nvenc->device.ptr = NULL;
+    nvenc->device.type = 0;
+}
+
+static int init_device(nvencoder_t *nvenc)
+{
+#if defined (NV_CUDACTX)
+    CUresult cures;
+    cuinit_t cunit;
+    cudevicecomputecapability_t cudevicecomputecapability;
+    cudeviceget_t cudeviceget;
+    cuctxcreate_t cuctxcreate;
+    int32_t sm_major, sm_minor;
+#endif
+#if defined (NV_D3DCTX)
+    HRESULT hr;
+    directd3dcreate9_t d3dcreate9;
+    D3DPRESENT_PARAMETERS d3dpp;
+#endif
+
+#if defined (NV_CUDACTX)
+    // Allocate CUDA context as basis
+    nvenc->device.type = NV_ENC_DEVICE_TYPE_CUDA;
+    nvenc->device.lib = LoadLibrary(NVCUDA_LIB);
+    if (nvenc->device.lib)
+    {
+        cunit =
+            (cuinit_t)GetProcAddress(nvenc->device.lib, "cuInit");
+        cudevicecomputecapability =
+            (cudevicecomputecapability_t)GetProcAddress(nvenc->device.lib, "cuDeviceComputeCapability");
+        cudeviceget =
+            (cudeviceget_t)GetProcAddress(nvenc->device.lib, "cuDeviceGet");
+        cuctxcreate =
+            (cuctxcreate_t)GetProcAddress(nvenc->device.lib, "cuCtxCreate");
+        if (cunit && cudevicecomputecapability && cudeviceget && cuctxcreate)
+        {
+            cures = cunit(0);
+            if (cures == CUDA_SUCCESS)
+            {
+                // Get a compatible, NVENC-present CUDA device
+				cures = cudeviceget(&nvenc->device.cudadevice, 0);
+				if (cures == CUDA_SUCCESS) {
+					cures = cudevicecomputecapability(&sm_major, &sm_minor, nvenc->device.cudadevice);
+					if ((cures == CUDA_SUCCESS) && (sm_major >= 3))
+					{
+                        // Create the CUDA Context
+                        cures = cuctxcreate(&nvenc->device.cudacontext, 0, nvenc->device.cudadevice);
+                        if (cures == CUDA_SUCCESS)
+                        {
+                            nvenc->device.ptr = (void*)nvenc->device.cudacontext;
+                            return 1;
+                        }
+                    }
+                }
+            }
+        }
+    }
+#endif // NV_CUDACTX
+
+    deinit_device(nvenc);
+
+#if defined (NV_D3DCTX)
+    // Allocate D3D context as basis
+    nvenc->device.type = NV_ENC_DEVICE_TYPE_DIRECTX;
+    nvenc->device.lib = LoadLibrary(TEXT("d3d9.dll"));
+    if (nvenc->device.lib)
+    {
+        d3dcreate9 =
+            (directd3dcreate9_t)GetProcAddress(nvenc->device.lib, "Direct3DCreate9");
+        if (d3dcreate9)
+        {
+            nvenc->device.d3d = d3dcreate9(D3D_SDK_VERSION);
+            if (nvenc->device.d3d)
+            {
+                // Create the Direct3D9 device and the swap chain. In this example, the swap
+                // chain is the same size as the current display mode. The format is RGB-32.
+                memset(&d3dpp, 0, sizeof(d3dpp));
+                d3dpp.Windowed             = TRUE;
+                d3dpp.BackBufferFormat     = D3DFMT_UNKNOWN;
+                d3dpp.BackBufferWidth      = 128;
+                d3dpp.BackBufferHeight     = 128;
+                d3dpp.BackBufferCount      = 0;
+                d3dpp.SwapEffect           = D3DSWAPEFFECT_COPY;
+                d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+                d3dpp.Flags                = D3DPRESENTFLAG_VIDEO;
+
+                hr = IDirect3D9_CreateDevice(
+                        nvenc->device.d3d,
+                        D3DADAPTER_DEFAULT,
+                        D3DDEVTYPE_HAL,
+                        NULL,
+                        D3DCREATE_MULTITHREADED | D3DCREATE_HARDWARE_VERTEXPROCESSING,
+                        &d3dpp,
+                        (IDirect3DDevice9**)&nvenc->device.d3ddevice);
+                if (SUCCEEDED(hr))
+                {
+                    nvenc->device.ptr = (void*)nvenc->device.d3ddevice;
+                    return 1;
+                }
+            }
+        }
+    }
+#endif // NV_D3DCTX
+
+	return AVERROR_EXTERNAL;
+}
+
+static int query_caps(nvencoder_t *nvenc)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+    uint32_t count;
+    uint32_t count_ret;
+
+    // Enumerate codec GUIDs
+    count = 0, count_ret = 0;
+    nvenc_status = nvenc->api.nvEncGetEncodeGUIDCount(nvenc->inst, &count);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        nvenc->codec_guids = (GUID *)av_mallocz(sizeof(GUID)* count);
+        if (nvenc->codec_guids)
+        {
+            nvenc_status = nvenc->api.nvEncGetEncodeGUIDs(nvenc->inst, nvenc->codec_guids, count, &count_ret);
+            if ((nvenc_status != NV_ENC_SUCCESS) || (count_ret == 0))
+            {
+				return AVERROR_EXTERNAL;
+            }
+            nvenc->num_codec_guids = count_ret;
+        }
+    }
+
+    // Enumerate codec profile GUIDs
+    count = 0, count_ret = 0;
+    nvenc_status = nvenc->api.nvEncGetEncodeProfileGUIDCount(nvenc->inst, NV_ENC_CODEC_H264_GUID, &count);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        nvenc->profile_guids = (GUID *)av_mallocz(sizeof(GUID)* count);;
+        if (nvenc->profile_guids)
+        {
+            nvenc_status = nvenc->api.nvEncGetEncodeProfileGUIDs(nvenc->inst, NV_ENC_CODEC_H264_GUID, nvenc->profile_guids, count, &count_ret);
+            if ((nvenc_status != NV_ENC_SUCCESS) || (count_ret == 0))
+            {
+				return AVERROR_EXTERNAL;
+            }
+            nvenc->num_preset_guids = count_ret;
+        }
+    }
+
+    // Enumerate codec preset GUIDs
+    count = 0, count_ret = 0;
+    nvenc_status = nvenc->api.nvEncGetEncodePresetCount(nvenc->inst, NV_ENC_CODEC_H264_GUID, &count);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        nvenc->preset_guids = (GUID *)av_mallocz(sizeof(GUID)* count);
+        if (nvenc->preset_guids)
+        {
+            nvenc_status = nvenc->api.nvEncGetEncodePresetGUIDs(nvenc->inst, NV_ENC_CODEC_H264_GUID, nvenc->preset_guids, count, &count_ret);
+            if ((nvenc_status != NV_ENC_SUCCESS) || (count_ret == 0))
+            {
+				return AVERROR_EXTERNAL;
+            }
+            nvenc->num_profile_guids = count_ret;
+        }
+    }
+
+    // Enumerate input formats
+    count = 0, count_ret = 0;
+    nvenc_status = nvenc->api.nvEncGetInputFormatCount(nvenc->inst, NV_ENC_CODEC_H264_GUID, &count);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        nvenc->buffer_fmts = (NV_ENC_BUFFER_FORMAT*)av_mallocz(sizeof(NV_ENC_BUFFER_FORMAT)* count);
+        if (nvenc->buffer_fmts)
+        {
+            nvenc_status = nvenc->api.nvEncGetInputFormats(nvenc->inst, NV_ENC_CODEC_H264_GUID, nvenc->buffer_fmts, count, &count_ret);
+            if ((nvenc_status != NV_ENC_SUCCESS) || (count_ret == 0))
+            {
+				return AVERROR_EXTERNAL;
+            }
+            nvenc->num_buffer_fmts = count_ret;
+        }
+    }
+
+    return 1;
+}
+
+static int open(nvencoder_t *nvenc)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+    nvencodeapicreateinstance_t encodeapicreateinst;
+    NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS open_encode_session_params;
+
+    // Dynamically load NVENC library
+    nvenc->lib = LoadLibrary(NVENCODEAPI_LIB);
+    if (!nvenc->lib)
+    {
+		return AVERROR_EXTERNAL;
+    }
+    encodeapicreateinst =
+        (nvencodeapicreateinstance_t)GetProcAddress(nvenc->lib, "NvEncodeAPICreateInstance");
+    if (!encodeapicreateinst)
+    {
+		return AVERROR_EXTERNAL;
+    }
+
+    // Initialize function table
+    nvenc->api.version = NV_ENCODE_API_FUNCTION_LIST_VER;
+    nvenc_status = encodeapicreateinst(&nvenc->api);
+    if (nvenc_status != NV_ENC_SUCCESS)
+    {
+		return AVERROR_EXTERNAL;
+    }
+
+    if (!init_device(nvenc))
+    {
+		return AVERROR_EXTERNAL;
+    }
+
+    // Open encoder session
+    memset(&open_encode_session_params, 0, sizeof(open_encode_session_params));
+    open_encode_session_params.version      = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
+    open_encode_session_params.apiVersion   = NVENCAPI_VERSION;
+    open_encode_session_params.device       = nvenc->device.ptr;
+    open_encode_session_params.deviceType   = nvenc->device.type;
+
+    nvenc_status = nvenc->api.nvEncOpenEncodeSessionEx(&open_encode_session_params, &nvenc->inst);
+    if (nvenc_status != NV_ENC_SUCCESS)
+    {
+		return AVERROR_EXTERNAL;
+    }
+
+    // Find encoder capabilities
+    if (!query_caps(nvenc))
+    {
+		return AVERROR_EXTERNAL;
+    }
+
+    return 1;
+}
+
+static int allocate_io(nvencoder_t *nvenc)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+    NV_ENC_CREATE_INPUT_BUFFER create_input_buffer;
+    NV_ENC_CREATE_BITSTREAM_BUFFER create_bitstream_buffer;
+
+    // Input buffer
+    memset(&create_input_buffer, 0, sizeof(create_input_buffer));
+    create_input_buffer.version    = NV_ENC_CREATE_INPUT_BUFFER_VER;
+    create_input_buffer.width      = nvenc->init_params.maxEncodeWidth;
+    create_input_buffer.height     = nvenc->init_params.maxEncodeHeight;
+    create_input_buffer.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_UNCACHED;
+    create_input_buffer.bufferFmt  = nvenc->buffer_fmt;
+
+    nvenc_status = nvenc->api.nvEncCreateInputBuffer(nvenc->inst, &create_input_buffer);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        nvenc->i_buffer = create_input_buffer.inputBuffer;
+        create_input_buffer.inputBuffer = NULL;
+    }
+
+    // Output buffer
+    memset(&create_bitstream_buffer, 0, sizeof(create_bitstream_buffer));
+    create_bitstream_buffer.version    = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
+    create_bitstream_buffer.size       = nvenc->init_params.maxEncodeWidth * nvenc->init_params.maxEncodeHeight;
+    create_bitstream_buffer.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
+
+    nvenc_status = nvenc->api.nvEncCreateBitstreamBuffer(nvenc->inst, &create_bitstream_buffer);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        nvenc->o_buffer = create_bitstream_buffer.bitstreamBuffer;
+        create_bitstream_buffer.bitstreamBuffer = NULL;
+    }
+
+    return 1;
+}
+
+static void deallocate_io(nvencoder_t *nvenc)
+{
+    // Output buffer
+    if (nvenc->o_buffer)
+    {
+        nvenc->api.nvEncDestroyBitstreamBuffer(nvenc->inst, nvenc->o_buffer);
+        nvenc->o_buffer = NULL;
+    }
+
+    // Input buffer
+    if (nvenc->i_buffer)
+    {
+        nvenc->api.nvEncDestroyInputBuffer(nvenc->inst, nvenc->i_buffer);
+        nvenc->i_buffer = NULL;
+    }
+}
+
+static void close(nvencoder_t *nvenc)
+{
+    if (nvenc->buffer_fmts)
+    {
+        av_freep(&nvenc->buffer_fmts);
+        nvenc->num_buffer_fmts = 0;
+    }
+    if (nvenc->preset_guids)
+    {
+        av_freep(&nvenc->preset_guids);
+        nvenc->num_codec_guids = 0;
+    }
+    if (nvenc->profile_guids)
+    {
+        av_freep(&nvenc->profile_guids);
+        nvenc->num_profile_guids = 0;
+    }
+    if (nvenc->codec_guids)
+    {
+        av_freep(&nvenc->codec_guids);
+        nvenc->num_codec_guids = 0;
+    }
+
+    if (nvenc->inst)
+    {
+        nvenc->api.nvEncDestroyEncoder(nvenc->inst);
+        nvenc->inst = NULL;
+    }
+
+    deinit_device(nvenc);
+
+    if (nvenc->lib)
+    {
+        FreeLibrary(nvenc->lib);
+        nvenc->lib = NULL;
+    }
+}
+
+static int initialize(nvencoder_t *nvenc, nvenc_cfg_t *nvenc_cfg)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+
+    //NV_ENC_CONFIG generic
+    nvenc->config.version                   = NV_ENC_CONFIG_VER;
+    nvenc->config.profileGUID               = map_profile(nvenc_cfg->profile);
+    nvenc->config.gopLength                 = nvenc_cfg->gopLength;
+    nvenc->config.frameIntervalP            = 1 + nvenc_cfg->numBFrames;
+    nvenc->config.frameFieldMode            = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
+    nvenc->config.mvPrecision               = NV_ENC_MV_PRECISION_QUARTER_PEL;
+
+    //NV_ENC_CODEC_CONFIG rate-control
+    nvenc->config.rcParams.version          = NV_ENC_RC_PARAMS_VER;
+    nvenc->config.rcParams.rateControlMode  = (NV_ENC_PARAMS_RC_MODE)nvenc_cfg->rateControl;
+    nvenc->config.rcParams.maxBitRate       = nvenc_cfg->peakBitRate;
+    nvenc->config.rcParams.averageBitRate   = nvenc_cfg->avgBitRate;
+    nvenc->config.rcParams.constQP.qpIntra  = nvenc_cfg->qpI;
+    nvenc->config.rcParams.constQP.qpInterP = nvenc_cfg->qpP;
+    nvenc->config.rcParams.constQP.qpInterB = nvenc_cfg->qpB;
+    nvenc->config.rcParams.minQP.qpIntra    = nvenc_cfg->qpMin;
+    nvenc->config.rcParams.minQP.qpInterP   = nvenc_cfg->qpMin;
+    nvenc->config.rcParams.minQP.qpInterB   = nvenc_cfg->qpMin;
+    nvenc->config.rcParams.maxQP.qpIntra    = nvenc_cfg->qpMax;
+    nvenc->config.rcParams.maxQP.qpInterP   = nvenc_cfg->qpMax;
+    nvenc->config.rcParams.maxQP.qpInterB   = nvenc_cfg->qpMax;
+
+    //NV_ENC_CODEC_CONFIG codec
+    nvenc->config.encodeCodecConfig.h264Config.outputAUD                  = nvenc_cfg->enableAUD;
+    nvenc->config.encodeCodecConfig.h264Config.disableSPSPPS              = nvenc_cfg->disableSPSPPS;
+    nvenc->config.encodeCodecConfig.h264Config.repeatSPSPPS               = nvenc_cfg->enableRepeatSPSPPS;
+    nvenc->config.encodeCodecConfig.h264Config.level                      = map_level(nvenc_cfg->level);
+    nvenc->config.encodeCodecConfig.h264Config.idrPeriod                  = nvenc_cfg->idrPeriod;
+    nvenc->config.encodeCodecConfig.h264Config.fmoMode                    = NV_ENC_H264_FMO_DISABLE;
+    nvenc->config.encodeCodecConfig.h264Config.maxNumRefFrames            = nvenc_cfg->numRefFrames;
+    nvenc->config.encodeCodecConfig.h264Config.chromaFormatIDC            = 1;
+    nvenc->config.encodeCodecConfig.h264Config.bdirectMode                = (NV_ENC_H264_BDIRECT_MODE)nvenc_cfg->bdirectMode;
+    nvenc->config.encodeCodecConfig.h264Config.adaptiveTransformMode      = (NV_ENC_H264_ADAPTIVE_TRANSFORM_MODE)nvenc_cfg->adaptiveTransformMode;
+    nvenc->config.encodeCodecConfig.h264Config.sliceMode                  = nvenc_cfg->sliceMode;
+    nvenc->config.encodeCodecConfig.h264Config.sliceModeData              = nvenc_cfg->sliceModeData;
+    nvenc->config.encodeCodecConfig.h264Config.outputBufferingPeriodSEI   = nvenc_cfg->enableSEIBufferPeriod;
+    nvenc->config.encodeCodecConfig.h264Config.outputPictureTimingSEI     = nvenc_cfg->enableSEIPictureTime;
+    nvenc->config.encodeCodecConfig.h264Config.disableDeblockingFilterIDC = nvenc_cfg->disableDeblockingFilterIDC;
+
+    //NV_ENC_INIT_PARAMS
+    nvenc->init_params.encodeConfig       = &nvenc->config;
+    nvenc->init_params.version            = NV_ENC_INITIALIZE_PARAMS_VER;
+    nvenc->init_params.encodeGUID         = NV_ENC_CODEC_H264_GUID;
+    nvenc->init_params.presetGUID         = NV_ENC_PRESET_HQ_GUID;
+    nvenc->init_params.encodeWidth        = nvenc_cfg->width;
+    nvenc->init_params.encodeHeight       = nvenc_cfg->height;
+    nvenc->init_params.darWidth           = nvenc_cfg->width;
+    nvenc->init_params.darHeight          = nvenc_cfg->height;
+    nvenc->init_params.frameRateNum       = nvenc_cfg->frameRateNum;
+    nvenc->init_params.frameRateDen       = nvenc_cfg->frameRateDen;
+    nvenc->init_params.enableEncodeAsync  = 0;
+    nvenc->init_params.enablePTD          = 1;
+    nvenc->init_params.maxEncodeWidth     = nvenc_cfg->width;
+    nvenc->init_params.maxEncodeHeight    = nvenc_cfg->height;
+
+    // Apply x264-style options that will override the above settings
+    map_x264_params(&nvenc->init_params, nvenc_cfg->x264_paramc, nvenc_cfg->x264_paramv);
+
+    nvenc_status = nvenc->api.nvEncInitializeEncoder(nvenc->inst, &nvenc->init_params);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        // Default to NV12 as preferred input format
+        nvenc->buffer_fmt = NV_ENC_BUFFER_FORMAT_NV12_PL;
+
+        return 1;
+    }
+
+	return AVERROR_EXTERNAL;
+}
+
+static int encode_frame(nvencoder_t *nvenc, nvenc_frame_t *nvenc_frame, bool *output, bool flush)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+    NV_ENC_PIC_PARAMS pic_params;
+
+    memset(&pic_params, 0, sizeof(pic_params));
+    if (flush)
+    {
+        pic_params.version         = NV_ENC_PIC_PARAMS_VER;
+        pic_params.encodePicFlags |= NV_ENC_PIC_FLAG_EOS;
+    }
+    else
+    {
+        pic_params.version         = NV_ENC_PIC_PARAMS_VER;
+        pic_params.inputWidth      = nvenc_frame->width;
+        pic_params.inputHeight     = nvenc_frame->height;
+        pic_params.inputBuffer     = nvenc->i_buffer;
+        pic_params.outputBitstream = nvenc->o_buffer;
+        pic_params.bufferFmt       = nvenc->buffer_fmt;
+        pic_params.pictureStruct   = NV_ENC_PIC_STRUCT_FRAME;
+        pic_params.frameIdx        = nvenc_frame->frame_idx;
+        if (nvenc_frame->force_idr)
+            pic_params.encodePicFlags |= NV_ENC_PIC_FLAG_FORCEIDR;
+        if (nvenc_frame->force_intra)
+            pic_params.encodePicFlags |= NV_ENC_PIC_FLAG_FORCEINTRA;
+    }
+
+    nvenc_status = nvenc->api.nvEncEncodePicture(nvenc->inst, &pic_params);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        *output = true;
+        return 1;
+    }
+    if (nvenc_status == NV_ENC_ERR_NEED_MORE_INPUT)
+    {
+        *output = false;
+        return 1;
+    }
+
+	return AVERROR_EXTERNAL;
+}
+
+static int feed_input(nvencoder_t *nvenc, uint8_t **planes, uint32_t *pitches, enum nvenc_pixfmt_t buffer_fmt)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+    NV_ENC_LOCK_INPUT_BUFFER lock_input_buffer;
+    uint8_t *src, *dst;
+    uint32_t src_pitch, dst_pitch, x, y;
+
+    memset(&lock_input_buffer, 0, sizeof(lock_input_buffer));
+    lock_input_buffer.version     = NV_ENC_LOCK_BITSTREAM_VER;
+    lock_input_buffer.inputBuffer = nvenc->i_buffer;
+
+    nvenc_status = nvenc->api.nvEncLockInputBuffer(nvenc->inst, &lock_input_buffer);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        dst = (uint8_t*)lock_input_buffer.bufferDataPtr;
+        dst_pitch = lock_input_buffer.pitch;
+
+        if (buffer_fmt == NVENC_FMT_NV12)
+        {
+            // Y
+            src = planes[0];
+            src_pitch = pitches[0];
+            for (y = 0; y < nvenc->init_params.encodeHeight; y++)
+            {
+                memcpy(dst, src, nvenc->init_params.encodeWidth);
+                dst += dst_pitch;
+                src += src_pitch;
+            }
+            // UV
+            src = planes[1];
+            src_pitch = pitches[1];
+            for (y = 0; y < nvenc->init_params.encodeHeight / 2; y++)
+            {
+                memcpy(dst, src, nvenc->init_params.encodeWidth);
+                dst += dst_pitch;
+                src += src_pitch;
+            }
+        }
+        else if (buffer_fmt == NVENC_FMT_YV12)
+        {
+            // Y
+            src = planes[0];
+            src_pitch = pitches[0];
+            for (y = 0; y < nvenc->init_params.encodeHeight; y++)
+            {
+                memcpy(dst, src, nvenc->init_params.encodeWidth);
+                dst += dst_pitch;
+                src += src_pitch;
+            }
+            // UV interleaving
+            for (y = 0; y < nvenc->init_params.encodeHeight / 2; y++)
+            {
+                for (x = 0; x < nvenc->init_params.encodeWidth; x += 2)
+                {
+                    dst[x]     = planes[1][(pitches[1] * y) + (x >> 1)];
+                    dst[x + 1] = planes[2][(pitches[2] * y) + (x >> 1)];
+                }
+                dst += dst_pitch;
+            }
+        }
+
+        nvenc->api.nvEncUnlockInputBuffer(nvenc->inst, nvenc->i_buffer);
+
+        return 1;
+    }
+
+	return AVERROR_EXTERNAL;
+}
+
+static int fetch_output(nvencoder_t *nvenc, nvenc_bitstream_t *nvenc_bitstream)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+    NV_ENC_LOCK_BITSTREAM lock_bitstream;
+    uint8_t *src;
+    uint32_t src_size;
+
+    memset(&lock_bitstream, 0, sizeof(lock_bitstream));
+    lock_bitstream.version         = NV_ENC_LOCK_BITSTREAM_VER;
+    lock_bitstream.doNotWait       = 0;
+    lock_bitstream.outputBitstream = nvenc->o_buffer;
+
+    nvenc_status = nvenc->api.nvEncLockBitstream(nvenc->inst, &lock_bitstream);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        src = (uint8_t*)lock_bitstream.bitstreamBufferPtr;
+        src_size = lock_bitstream.bitstreamSizeInBytes;
+
+        // copy bitstream out
+        if (nvenc_bitstream->payload &&
+            nvenc_bitstream->payload_size >= src_size)
+        {
+            memcpy(nvenc_bitstream->payload, src, src_size);
+            nvenc_bitstream->payload_size  = src_size;
+            nvenc_bitstream->pic_idx  = lock_bitstream.frameIdx;
+            nvenc_bitstream->pic_type = lock_bitstream.pictureType;
+        }
+
+        nvenc->api.nvEncUnlockBitstream(nvenc->inst, nvenc->o_buffer);
+
+        return 1;
+    }
+
+	return AVERROR_EXTERNAL;
+}
+
+static int reconfig(nvencoder_t *nvenc, nvenc_cfg_t *nvenc_cfg)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+    NV_ENC_RECONFIGURE_PARAMS reconfig_params;
+
+    // Update initial encoder parameters that likely changed
+    nvenc->init_params.encodeWidth  = nvenc_cfg->width;
+    nvenc->init_params.encodeHeight = nvenc_cfg->height;
+    nvenc->init_params.darWidth     = nvenc_cfg->width;
+    nvenc->init_params.darWidth     = nvenc_cfg->height;
+    nvenc->init_params.frameRateNum = nvenc_cfg->frameRateNum;
+    nvenc->init_params.frameRateDen = nvenc_cfg->frameRateDen;
+    nvenc->init_params.encodeConfig->rcParams.averageBitRate = nvenc_cfg->avgBitRate;
+    nvenc->init_params.encodeConfig->rcParams.maxBitRate = nvenc_cfg->peakBitRate;
+
+    // Update x264-style options that will override the above settings
+    map_x264_params(&nvenc->init_params, nvenc_cfg->x264_paramc, nvenc_cfg->x264_paramv);
+
+    memset(&reconfig_params, 0, sizeof(reconfig_params));
+    reconfig_params.version      = NV_ENC_RECONFIGURE_PARAMS_VER;
+    reconfig_params.resetEncoder = 1;
+    memcpy(&reconfig_params.reInitEncodeParams, &nvenc->init_params, sizeof(nvenc->init_params));
+
+    nvenc_status = nvenc->api.nvEncReconfigureEncoder(nvenc->inst, &reconfig_params);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        return 1;
+    }
+
+	return AVERROR_EXTERNAL;
+}
+
+static int get_header(nvencoder_t *nvenc, uint8_t **header, size_t *header_size)
+{
+    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
+    NV_ENC_SEQUENCE_PARAM_PAYLOAD seq_param_payload;
+
+    nvenc_status = nvenc->api.nvEncGetSequenceParams(nvenc->inst, &seq_param_payload);
+    if (nvenc_status == NV_ENC_SUCCESS)
+    {
+        // copy header out
+        if ((header && header_size) &&
+            (*header_size >= (size_t)seq_param_payload.outSPSPPSPayloadSize))
+        {
+            *header_size = (size_t)seq_param_payload.outSPSPPSPayloadSize;
+            memcpy(*header, seq_param_payload.spsppsBuffer, *header_size);
+            return 1;
+        }
+    }
+
+	return AVERROR_EXTERNAL;
+}
+
+
+/**
+ * Creates and initializes a new encode session.
+ *
+ * @param nvenc_cfg The encoder initialization parameters
+ * @return The encoder instance, NULL on failure
+ */
+nvenc_t* nvenc_open(nvenc_cfg_t *nvenc_cfg)
+{
+    nvencoder_t *_nvenc = (nvencoder_t *)av_mallocz(sizeof(nvencoder_t));
+    if (_nvenc)
+    {
+        if (open(_nvenc)                  &&
+            initialize(_nvenc, nvenc_cfg) &&
+            allocate_io(_nvenc))
+        {
+            return (nvenc_t*)_nvenc;
+        }
+        deallocate_io(_nvenc);
+        close(_nvenc);
+        av_freep(&_nvenc);
+    }
+    return NULL;
+}
+
+/**
+ * Re-initializes an existing encode session with new parameters.
+ * 
+ * Only a subset of encoding parameters can be changed, which includes, not are
+ * not necessarily limited to: dimensions, framerate, and bitrate.
+ *
+ * @param nvenc The encoder instance
+ * @param nvenc_cfg The encoder initialization parameters
+ * @return 0 on success, negative on failure
+ */
+int nvenc_reconfig(nvenc_t *nvenc, nvenc_cfg_t *nvenc_cfg)
+{
+    nvencoder_t *_nvenc = (nvencoder_t*)nvenc;
+    if (_nvenc)
+    {
+        if (reconfig(_nvenc, nvenc_cfg))
+        {
+            return 0;
+        }
+    }
+	return AVERROR_EXTERNAL;
+}
+
+/**
+ * Encodes a single picture with the given encode input and encode parameters
+ *
+ * @param nvenc The encoder instance
+ * @param nvenc_frame The input data and config for the current picture
+ * @param nvenc_bitstream The encoded output data
+ * @return 0 on success, negative on failure, 1 on require more input
+ */
+int nvenc_encode(nvenc_t *nvenc, nvenc_frame_t *nvenc_frame, nvenc_bitstream_t *nvenc_bitstream)
+{
+    bool output;
+    nvencoder_t *_nvenc = (nvencoder_t*)nvenc;
+    if (_nvenc)
+    {
+        // Simple synchronous encoding
+        if (feed_input(_nvenc, nvenc_frame->planes, nvenc_frame->stride, nvenc_frame->format) &&
+            encode_frame(_nvenc, nvenc_frame, &output, false))
+        {
+            if (!output)
+            {
+                return 1;
+            }
+            if (fetch_output(_nvenc, nvenc_bitstream))
+            {
+                return 0;
+            }
+        }
+    }
+
+	return AVERROR_EXTERNAL;
+}
+
+/**
+* Retrieves the codec bitstream headers for the encode session.
+*
+* @param nvenc The encoder instance
+* @param nvenc_header The buffer to hold the bitstream header
+* @return 0 on success, negative on failure
+*/
+int nvenc_header(nvenc_t *nvenc, nvenc_header_t *nvenc_header)
+{
+    nvencoder_t *_nvenc = (nvencoder_t*)nvenc;
+    if (_nvenc)
+    {
+        if (get_header(_nvenc, &nvenc_header->payload, &nvenc_header->payload_size))
+        {
+            return 0;
+        }
+    }
+	return AVERROR_EXTERNAL;
+}
+
+/**
+* Closes the encode session and releases its resources.
+*
+* @param nvenc The encoder instance
+*/
+void nvenc_close(nvenc_t *nvenc)
+{
+    bool output;
+    nvencoder_t *_nvenc = (nvencoder_t*)nvenc;
+    if (_nvenc)
+    {
+        // Flush encoder
+        encode_frame(_nvenc, NULL, &output, true);
+
+        deallocate_io(_nvenc);
+        close(_nvenc);
+        av_freep(&_nvenc);
+    }
+}
diff --git a/libavcodec/nvencoder.h b/libavcodec/nvencoder.h
new file mode 100644
index 0000000..787ba35
--- /dev/null
+++ b/libavcodec/nvencoder.h
@@ -0,0 +1,98 @@
+/* 
+* NVENC wrapper implementation.
+*
+* Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+*
+* 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, version 2.1, as published by the Free Software Foundation.
+*
+* 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NVENCODER_H
+#define _NVENCODER_H
+
+#include "nvEncodeAPI.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+#if !defined (_WIN32)
+#define         NVENCAPI
+typedef void*   HINSTANCE;
+typedef void*   HANDLE;
+#endif
+
+// Allow either CUDA/D3D or both as context to encoding interface
+#define NV_CUDACTX
+#if defined (_WIN32)
+#define NV_D3DCTX
+#endif
+
+#if defined (NV_D3DCTX)
+#include <D3D9.h>
+#endif
+#if defined (NV_CUDACTX)
+//#include "cuda.h"
+#ifdef _WIN32
+#define CUDAAPI __stdcall
+#else
+#define CUDAAPI
+#endif
+
+#define CUDA_SUCCESS 0
+
+typedef int CUresult;
+typedef int CUdevice;                                     
+typedef struct CUctx_st *CUcontext; 	 
+
+#endif
+
+// Main encoding context
+typedef struct nvencoder_t
+{
+    HINSTANCE                   lib;
+    NV_ENCODE_API_FUNCTION_LIST api;
+
+    HANDLE                      inst;
+    GUID                       *codec_guids;
+    GUID                       *profile_guids;
+    GUID                       *preset_guids;
+    NV_ENC_BUFFER_FORMAT       *buffer_fmts;
+    uint32_t                    num_codec_guids;
+    uint32_t                    num_profile_guids;
+    uint32_t                    num_preset_guids;
+    uint32_t                    num_buffer_fmts;
+
+    NV_ENC_INITIALIZE_PARAMS    init_params;
+    NV_ENC_CONFIG               config;
+    NV_ENC_BUFFER_FORMAT        buffer_fmt;
+
+    NV_ENC_INPUT_PTR            i_buffer;
+    NV_ENC_OUTPUT_PTR           o_buffer;
+
+    struct
+    {
+        HINSTANCE               lib;
+#if defined (NV_D3DCTX)
+        IDirect3D9             *d3d;
+        IDirect3DDevice9       *d3ddevice;
+#endif
+#if defined (NV_CUDACTX)
+        CUdevice                cudadevice;
+        CUcontext               cudacontext;
+#endif
+        void                   *ptr;
+        NV_ENC_DEVICE_TYPE      type;
+    } device;
+} nvencoder_t;
+
+#endif // _NVENCODER_H
diff --git a/libavcodec/nvencoder_utils.c b/libavcodec/nvencoder_utils.c
new file mode 100644
index 0000000..384112c
--- /dev/null
+++ b/libavcodec/nvencoder_utils.c
@@ -0,0 +1,344 @@
+/*
+* Helper functions for NVENC wrapper
+*
+* Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+*
+* 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, version 2.1, as published by the Free Software Foundation.
+*
+* 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "nvencoder_utils.h"
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <libavutil/avutil.h>
+
+// List of all current x264 options
+typedef struct x264_params_t
+{
+    // Presets
+    char                           *profile;
+    char                           *preset;
+    char                           *tune;
+
+    // Frame
+    uint32_t                        keyint;
+    uint32_t                        min_keyint;
+    bool                            intra_refresh;
+    uint32_t                        bframes;
+    bool                            open_gop;
+    bool                            no_cabac;
+    uint32_t                        ref;
+    bool                            no_deblock;
+    uint32_t                        slices;
+
+    // Rate control
+    uint32_t                        qp;
+    uint32_t                        bitrate;
+    uint32_t                        vbv_maxrate;
+    uint32_t                        vbv_bufsize;
+    float                           vbv_init;
+    uint32_t                        qpmin;
+    uint32_t                        qpmax;
+    float                           ipratio;
+    float                           pbratio;
+
+    // Input/Output
+    char                           *output;
+    char                           *input_fmt;
+    char                           *input_csp;
+    char                           *output_csp;
+    uint32_t                        input_depth;
+    char                           *input_range;
+    char                           *fps;
+    uint32_t                        seek;
+    uint32_t                        frames;
+    float                           level;
+    bool                            aud;
+} x264_params_t;
+
+static bool guidcmp(const GUID *guid1, const GUID *guid2)
+{
+    return memcmp(guid1, guid2, sizeof(GUID)) == 0 ? true : false;
+}
+
+static GUID map_profile(const char *profile)
+{
+    if (!strncmp(profile, "baseline", 8))
+        return NV_ENC_H264_PROFILE_BASELINE_GUID;
+    if (!strncmp(profile, "main",     4))
+        return NV_ENC_H264_PROFILE_MAIN_GUID;
+    if (!strncmp(profile, "high",     4))
+        return NV_ENC_H264_PROFILE_HIGH_GUID;
+
+    return NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID;
+}
+static GUID map_preset(const char *profile)
+{
+    // all the fast presets
+    if (strstr(profile, "fast"))
+        return NV_ENC_PRESET_HP_GUID;
+
+    // all the slow presets
+    if (strstr(profile, "slow"))
+        return NV_ENC_PRESET_HQ_GUID;
+
+    return NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
+}
+static GUID map_tune(const char *tune, const GUID *cur_preset)
+{
+    // quality
+    if (!strncmp(tune, "psnr", 4) || !strncmp(tune, "ssim", 4))
+        return NV_ENC_PRESET_HQ_GUID;
+
+    // low-latency
+    if (!strncmp(tune, "zerolatency", 11))
+    {
+        if (guidcmp(cur_preset, &NV_ENC_PRESET_HQ_GUID))
+            return NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
+        else if (guidcmp(cur_preset, &NV_ENC_PRESET_HP_GUID))
+            return NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
+        else
+            return NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
+    }
+
+    return NV_ENC_PRESET_DEFAULT_GUID;
+}
+
+static bool parse_x264_params(x264_params_t *x264_params, char *x264_opt, char *x264_arg)
+{
+    if (!strcmp(x264_opt, "profile"))
+        x264_params->profile = x264_arg;
+    if (!strcmp(x264_opt, "preset"))
+        x264_params->preset = x264_arg;
+
+    if (!strcmp(x264_opt, "keyint"))
+        x264_params->keyint = atoi(x264_arg);
+    if (!strcmp(x264_opt, "min-keyint"))
+        x264_params->min_keyint = atoi(x264_arg);
+    if (!strcmp(x264_opt, "intra-refresh"))
+        x264_params->intra_refresh = true;
+    if (!strcmp(x264_opt, "bframes"))
+        x264_params->bframes = atoi(x264_arg);
+    if (!strcmp(x264_opt, "open-gop"))
+        x264_params->open_gop = true;
+    if (!strcmp(x264_opt, "no-cabac"))
+        x264_params->no_cabac = true;
+    if (!strcmp(x264_opt, "ref"))
+        x264_params->ref = atoi(x264_arg);
+    if (!strcmp(x264_opt, "no-deblock"))
+        x264_params->no_deblock = true;
+    if (!strcmp(x264_opt, "slices"))
+        x264_params->slices = atoi(x264_arg);
+
+    if (!strcmp(x264_opt, "qp"))
+        x264_params->qp = atoi(x264_arg);
+    if (!strcmp(x264_opt, "bitrate"))
+        x264_params->bitrate = atoi(x264_arg);
+    if (!strcmp(x264_opt, "vbv-maxrate"))
+        x264_params->vbv_maxrate = atoi(x264_arg);
+    if (!strcmp(x264_opt, "vbv-bufsize"))
+        x264_params->vbv_bufsize = atoi(x264_arg);
+    if (!strcmp(x264_opt, "vbv-init"))
+        x264_params->vbv_init = (float)atof(x264_arg);
+    if (!strcmp(x264_opt, "qpmin"))
+        x264_params->qpmin = atoi(x264_arg);
+    if (!strcmp(x264_opt, "qpmax"))
+        x264_params->qpmax = atoi(x264_arg);
+    if (!strcmp(x264_opt, "ipratio"))
+        x264_params->ipratio = (float)atof(x264_arg);
+    if (!strcmp(x264_opt, "pbratio"))
+        x264_params->pbratio = (float)atof(x264_arg);
+
+    if (!strcmp(x264_opt, "level"))
+        x264_params->level = (float)atof(x264_arg);
+    if (!strcmp(x264_opt, "aud"))
+        x264_params->aud = true;
+
+    return true;
+}
+
+static bool map_x264_to_nvenc(NV_ENC_INITIALIZE_PARAMS *nvenc_init_params, const x264_params_t *x264_params)
+{
+    uint32_t qp_ipdiff = (uint32_t)(6 * log2f(x264_params->ipratio > 0.f ? x264_params->ipratio : 1.4f));
+    uint32_t qp_pbdiff = (uint32_t)(6 * log2f(x264_params->pbratio > 0.f ? x264_params->pbratio : 1.3f));
+
+    // Preset
+    if (x264_params->profile)
+    {
+        nvenc_init_params->encodeConfig->profileGUID = map_profile(x264_params->profile);
+    }
+    if (x264_params->preset)
+    {
+        nvenc_init_params->presetGUID = map_preset(x264_params->preset);
+    }
+    if (x264_params->tune)
+    {
+        nvenc_init_params->presetGUID = map_tune(x264_params->tune, &nvenc_init_params->presetGUID);
+    }
+
+    // Frame
+    if ((x264_params->keyint > 0) || (x264_params->min_keyint > 0))
+    {
+        if ((x264_params->keyint == 0) || (x264_params->keyint > x264_params->min_keyint))
+            nvenc_init_params->encodeConfig->gopLength = x264_params->min_keyint;
+        else
+            nvenc_init_params->encodeConfig->gopLength = x264_params->keyint;
+        av_log(NULL, AV_LOG_INFO, "%s=%u\n", "gopLength", nvenc_init_params->encodeConfig->gopLength);
+    }
+    if (x264_params->intra_refresh)
+    {
+        const uint32_t fps = nvenc_init_params->frameRateNum / nvenc_init_params->frameRateDen;
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.enableIntraRefresh = 1;
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.intraRefreshCnt    = fps;
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.intraRefreshPeriod = fps;
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "enableIntraRefresh", fps);
+    }
+    if (x264_params->bframes > 0)
+    {
+        nvenc_init_params->encodeConfig->frameIntervalP = 0 + 1 + x264_params->bframes;
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "frameIntervalP",
+            nvenc_init_params->encodeConfig->frameIntervalP);
+    }
+    if (x264_params->open_gop)
+    {
+        nvenc_init_params->encodeConfig->gopLength = NVENC_INFINITE_GOPLENGTH;
+		av_log(NULL, AV_LOG_INFO, "%s=%s\n", "gopLength", "NVENC_INFINITE_GOPLENGTH");
+    }
+    if (x264_params->no_cabac)
+    {
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC;
+		av_log(NULL, AV_LOG_INFO, "%s=%s\n", "entropyCodingMode", "NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC");
+    }
+    if (x264_params->ref > 0)
+    {
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.maxNumRefFrames = x264_params->ref;
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "maxNumRefFrames",
+            nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.maxNumRefFrames);
+    }
+    if (x264_params->no_deblock > 0)
+    {
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.disableDeblockingFilterIDC = x264_params->no_deblock;
+		av_log(NULL, AV_LOG_INFO, "%s=%x\n", "disableDeblockingFilterIDC",
+            nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.disableDeblockingFilterIDC);
+    }
+    if (x264_params->slices > 0)
+    {
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.sliceMode = 3;
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.sliceModeData = x264_params->slices;
+		av_log(NULL, AV_LOG_INFO, "%s=%u,%s=%u\n",
+            "sliceMode", nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.sliceMode,
+            "sliceModeData", nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.maxNumRefFrames);
+    }
+
+    // Rate control
+    if (x264_params->qp > 0)
+    {
+        nvenc_init_params->encodeConfig->rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
+        nvenc_init_params->encodeConfig->rcParams.constQP.qpInterP = x264_params->qp;
+        nvenc_init_params->encodeConfig->rcParams.constQP.qpInterB = x264_params->qp + qp_pbdiff;
+        nvenc_init_params->encodeConfig->rcParams.constQP.qpIntra  = x264_params->qp - qp_ipdiff;
+		av_log(NULL, AV_LOG_INFO, "%s=%u,%s=%u,%s=%u\n",
+            "constQP.qpInterP", nvenc_init_params->encodeConfig->rcParams.constQP.qpInterP,
+            "constQP.qpInterB", nvenc_init_params->encodeConfig->rcParams.constQP.qpInterB,
+            "constQP.qpIntra" , nvenc_init_params->encodeConfig->rcParams.constQP.qpIntra);
+    }
+    if (x264_params->bitrate > 0)
+    {
+        nvenc_init_params->encodeConfig->rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR;
+        nvenc_init_params->encodeConfig->rcParams.averageBitRate = x264_params->bitrate;
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "averageBitRate",
+            nvenc_init_params->encodeConfig->rcParams.averageBitRate);
+    }
+    if (x264_params->vbv_maxrate > 0)
+    {
+        nvenc_init_params->encodeConfig->rcParams.maxBitRate = x264_params->vbv_maxrate;
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "maxBitRate",
+            nvenc_init_params->encodeConfig->rcParams.maxBitRate);
+    }
+    if (x264_params->vbv_bufsize > 0)
+    {
+        nvenc_init_params->encodeConfig->rcParams.vbvBufferSize = x264_params->vbv_bufsize;
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "vbvBufferSize",
+            nvenc_init_params->encodeConfig->rcParams.vbvBufferSize);
+    }
+    if (x264_params->vbv_init > 0.f)
+    {
+        nvenc_init_params->encodeConfig->rcParams.vbvInitialDelay = (uint32_t)x264_params->vbv_init;
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "vbvInitialDelay",
+            nvenc_init_params->encodeConfig->rcParams.vbvInitialDelay);
+    }
+    if (x264_params->qpmin > 0.f)
+    {
+        nvenc_init_params->encodeConfig->rcParams.enableMinQP = 1;
+        nvenc_init_params->encodeConfig->rcParams.minQP.qpInterP = x264_params->qpmin;
+        nvenc_init_params->encodeConfig->rcParams.minQP.qpInterB = x264_params->qpmin;
+        nvenc_init_params->encodeConfig->rcParams.minQP.qpIntra  = x264_params->qpmin;
+		av_log(NULL, AV_LOG_INFO, "%s=%u,%s=%u,%s=%u\n",
+            "minQP.qpInterP", nvenc_init_params->encodeConfig->rcParams.minQP.qpInterP,
+            "minQP.qpInterB", nvenc_init_params->encodeConfig->rcParams.minQP.qpInterB,
+            "minQP.qpIntra" , nvenc_init_params->encodeConfig->rcParams.minQP.qpIntra);
+    }
+    if (x264_params->qpmax > 0.f)
+    {
+        nvenc_init_params->encodeConfig->rcParams.enableMaxQP = 1;
+        nvenc_init_params->encodeConfig->rcParams.maxQP.qpInterP = x264_params->qpmax;
+        nvenc_init_params->encodeConfig->rcParams.maxQP.qpInterB = x264_params->qpmax;
+        nvenc_init_params->encodeConfig->rcParams.maxQP.qpIntra  = x264_params->qpmax;
+		av_log(NULL, AV_LOG_INFO, "%s=%u,%s=%u,%s=%u\n",
+            "maxQP.qpInterP", nvenc_init_params->encodeConfig->rcParams.maxQP.qpInterP,
+            "maxQP.qpInterB", nvenc_init_params->encodeConfig->rcParams.maxQP.qpInterB,
+            "maxQP.qpIntra" , nvenc_init_params->encodeConfig->rcParams.maxQP.qpIntra);
+    }
+
+    if (x264_params->level > 0.f)
+    {
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.level =
+            (uint32_t)(x264_params->level * 10.f);
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "level",
+            nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.level);
+    }
+    if (x264_params->aud)
+    {
+        nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.outputAUD = x264_params->aud;
+		av_log(NULL, AV_LOG_INFO, "%s=%u\n", "aud",
+            nvenc_init_params->encodeConfig->encodeCodecConfig.h264Config.outputAUD);
+    }
+
+    return false;
+}
+
+bool map_x264_params(NV_ENC_INITIALIZE_PARAMS *nvenc_init_params, uint32_t argc, char *argv[])
+{
+    x264_params_t *x264_params;
+    uint32_t i;
+
+    x264_params = av_mallocz(sizeof(x264_params_t));
+    if (x264_params)
+    {
+        // First, parse all understandable options (that appear in any order)
+        for (i = 0; i < argc; i += 2)
+        {
+            parse_x264_params(x264_params, argv[i], argv[i + 1]);
+        }
+        // Second, map and apply the x264 options to nvenc all at once
+        map_x264_to_nvenc(nvenc_init_params, x264_params);
+
+        av_free(x264_params);
+
+        return true;
+    }
+
+    return false;
+}
diff --git a/libavcodec/nvencoder_utils.h b/libavcodec/nvencoder_utils.h
new file mode 100644
index 0000000..b561b39
--- /dev/null
+++ b/libavcodec/nvencoder_utils.h
@@ -0,0 +1,30 @@
+/*
+* Helper functions for NVENC wrapper
+*
+* Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+*
+* 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, version 2.1, as published by the Free Software Foundation.
+*
+* 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NVENCODER_UTILS_H
+#define _NVENCODER_UTILS_H
+
+#include "nvEncodeAPI.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+bool map_x264_params(NV_ENC_INITIALIZE_PARAMS *nvenc_init_params, uint32_t argc, char *argv[]);
+
+#endif //_NVENCODER_UTILS_H
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index c781c8a..6e2e9a3 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -1997,7 +1997,7 @@ AVOutputFormat ff_matroska_muxer = {
     .priv_data_size    = sizeof(MatroskaMuxContext),
     .audio_codec       = CONFIG_LIBVORBIS_ENCODER ?
                          AV_CODEC_ID_VORBIS : AV_CODEC_ID_AC3,
-    .video_codec       = CONFIG_LIBX264_ENCODER ?
+    .video_codec       = (CONFIG_LIBX264_ENCODER || CONFIG_LIBNVENC_ENCODER) ?
                          AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
     .write_header      = mkv_write_header,
     .write_packet      = mkv_write_flush_packet,
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 9445417..f1ba453 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -5117,7 +5117,7 @@ AVOutputFormat ff_mov_muxer = {
     .extensions        = "mov",
     .priv_data_size    = sizeof(MOVMuxContext),
     .audio_codec       = AV_CODEC_ID_AAC,
-    .video_codec       = CONFIG_LIBX264_ENCODER ?
+    .video_codec       = (CONFIG_LIBX264_ENCODER || CONFIG_LIBNVENC_ENCODER) ?
                          AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
     .write_header      = mov_write_header,
     .write_packet      = mov_write_packet,
@@ -5155,7 +5155,7 @@ AVOutputFormat ff_mp4_muxer = {
     .extensions        = "mp4",
     .priv_data_size    = sizeof(MOVMuxContext),
     .audio_codec       = AV_CODEC_ID_AAC,
-    .video_codec       = CONFIG_LIBX264_ENCODER ?
+    .video_codec       = (CONFIG_LIBX264_ENCODER || CONFIG_LIBNVENC_ENCODER) ?
                          AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
     .write_header      = mov_write_header,
     .write_packet      = mov_write_packet,
@@ -5173,7 +5173,7 @@ AVOutputFormat ff_psp_muxer = {
     .extensions        = "mp4,psp",
     .priv_data_size    = sizeof(MOVMuxContext),
     .audio_codec       = AV_CODEC_ID_AAC,
-    .video_codec       = CONFIG_LIBX264_ENCODER ?
+    .video_codec       = (CONFIG_LIBX264_ENCODER || CONFIG_LIBNVENC_ENCODER) ?
                          AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
     .write_header      = mov_write_header,
     .write_packet      = mov_write_packet,


More information about the ffmpeg-devel mailing list