summaryrefslogtreecommitdiff
path: root/libavcodec/nvenc.c
diff options
context:
space:
mode:
authorPhilip Langdale <philipl@overt.org>2015-07-01 21:09:57 -0700
committerBtbN <btbn@btbn.de>2015-07-05 13:51:56 +0200
commit671bdd4b0977c6cc77bdc55883ac841a7c4af802 (patch)
tree57ff45c5c33c99e6f3d885da6fa05834624bf2dc /libavcodec/nvenc.c
parent5233f2534ca585614e413e78cb798bd079d4b26d (diff)
avcodec/nvenc: Add support for H.264 High 444 Predictive encoding
Newer versions of the nvenc hardware support The High 444 Predictive profile of H.264, and can also do lossless encoding under this profile if desired. This change introduces support for the profile, and exposes the appropriate presets for requesting lossless encoding. I tested lossless by generating a baseline sample with testsrc converted to raw yuv444p, then encoded the sample with nvenc, then did a framemd5 comparision of both the raw video and the nvenc encode. The framemd5 reports were identical. Signed-off-by: Philip Langdale <philipl@overt.org> Signed-off-by: Timo Rothenpieler <timo@rothenpieler.org>
Diffstat (limited to 'libavcodec/nvenc.c')
-rw-r--r--libavcodec/nvenc.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index a5652c545a..53625a21bd 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -401,7 +401,7 @@ static av_cold int nvenc_check_cuda(AVCodecContext *avctx)
switch (avctx->codec->id) {
case AV_CODEC_ID_H264:
- target_smver = 0x30;
+ target_smver = avctx->pix_fmt == AV_PIX_FMT_YUV444P ? 0x52 : 0x30;
break;
case AV_CODEC_ID_H265:
target_smver = 0x52;
@@ -552,6 +552,7 @@ static av_cold int nvenc_encode_init(AVCodecContext *avctx)
int surfaceCount = 0;
int i, num_mbs;
int isLL = 0;
+ int lossless = 0;
int res = 0;
int dw, dh;
@@ -627,10 +628,16 @@ static av_cold int nvenc_encode_init(AVCodecContext *avctx)
} else if (!strcmp(ctx->preset, "llhq")) {
encoder_preset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
isLL = 1;
+ } else if (!strcmp(ctx->preset, "lossless")) {
+ encoder_preset = NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
+ lossless = 1;
+ } else if (!strcmp(ctx->preset, "losslesshp")) {
+ encoder_preset = NV_ENC_PRESET_LOSSLESS_HP_GUID;
+ lossless = 1;
} else if (!strcmp(ctx->preset, "default")) {
encoder_preset = NV_ENC_PRESET_DEFAULT_GUID;
} else {
- av_log(avctx, AV_LOG_FATAL, "Preset \"%s\" is unknown! Supported presets: hp, hq, bd, ll, llhp, llhq, default\n", ctx->preset);
+ av_log(avctx, AV_LOG_FATAL, "Preset \"%s\" is unknown! Supported presets: hp, hq, bd, ll, llhp, llhq, lossless, losslesshp, default\n", ctx->preset);
res = AVERROR(EINVAL);
goto error;
}
@@ -753,7 +760,16 @@ static av_cold int nvenc_encode_init(AVCodecContext *avctx)
if (avctx->rc_max_rate > 0)
ctx->encode_config.rcParams.maxBitRate = avctx->rc_max_rate;
- if (ctx->cbr) {
+ if (lossless) {
+ ctx->encode_config.encodeCodecConfig.h264Config.qpPrimeYZeroTransformBypassFlag = 1;
+ ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
+ ctx->encode_config.rcParams.constQP.qpInterB = 0;
+ ctx->encode_config.rcParams.constQP.qpInterP = 0;
+ ctx->encode_config.rcParams.constQP.qpIntra = 0;
+
+ avctx->qmin = -1;
+ avctx->qmax = -1;
+ } else if (ctx->cbr) {
if (!ctx->twopass) {
ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR;
} else if (ctx->twopass == 1 || isLL) {
@@ -817,6 +833,9 @@ static av_cold int nvenc_encode_init(AVCodecContext *avctx)
if (!ctx->profile) {
switch (avctx->profile) {
+ case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID;
+ break;
case FF_PROFILE_H264_BASELINE:
ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
break;
@@ -842,6 +861,9 @@ static av_cold int nvenc_encode_init(AVCodecContext *avctx)
} else if (!strcmp(ctx->profile, "baseline")) {
ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
avctx->profile = FF_PROFILE_H264_BASELINE;
+ } else if (!strcmp(ctx->profile, "high444p")) {
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID;
+ avctx->profile = FF_PROFILE_H264_HIGH_444_PREDICTIVE;
} else {
av_log(avctx, AV_LOG_FATAL, "Profile \"%s\" is unknown! Supported profiles: high, main, baseline\n", ctx->profile);
res = AVERROR(EINVAL);
@@ -849,6 +871,8 @@ static av_cold int nvenc_encode_init(AVCodecContext *avctx)
}
}
+ ctx->encode_config.encodeCodecConfig.h264Config.chromaFormatIDC = avctx->profile == FF_PROFILE_H264_HIGH_444_PREDICTIVE ? 3 : 1;
+
if (ctx->level) {
res = input_string_to_uint32(avctx, nvenc_h264_level_pairs, ctx->level, &ctx->encode_config.encodeCodecConfig.h264Config.level);
@@ -1378,6 +1402,7 @@ static int nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
static const enum AVPixelFormat pix_fmts_nvenc[] = {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NV12,
+ AV_PIX_FMT_YUV444P,
AV_PIX_FMT_NONE
};