[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(¶m_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(¶m_dict);
+ }
+ }
+ // x264-style extra options
+ if (nvenc_ctx->x264_opts) {
+ AVDictionary *param_dict = NULL;
+ AVDictionaryEntry *param_entry = NULL;
+
+ if (!av_dict_parse_string(¶m_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(¶m_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