avcodec/nvenc: added support for 10 bit HEVC encoding

Signed-off-by: Timo Rothenpieler <timo@rothenpieler.org>
This commit is contained in:
Oliver Collyer 2016-08-25 16:18:03 +01:00 committed by Timo Rothenpieler
parent 325e56479f
commit d1bf8a3aa8
4 changed files with 78 additions and 7 deletions

View File

@ -76,13 +76,21 @@
const enum AVPixelFormat ff_nvenc_pix_fmts[] = {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NV12,
AV_PIX_FMT_P010,
AV_PIX_FMT_YUV444P,
AV_PIX_FMT_YUV444P16,
#if CONFIG_CUDA
AV_PIX_FMT_CUDA,
#endif
AV_PIX_FMT_NONE
};
#define IS_10BIT(pix_fmt) (pix_fmt == AV_PIX_FMT_P010 || \
pix_fmt == AV_PIX_FMT_YUV444P16)
#define IS_YUV444(pix_fmt) (pix_fmt == AV_PIX_FMT_YUV444P || \
pix_fmt == AV_PIX_FMT_YUV444P16)
static const struct {
NVENCSTATUS nverr;
int averr;
@ -273,7 +281,7 @@ static int nvenc_check_capabilities(AVCodecContext *avctx)
}
ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_YUV444_ENCODE);
if (ctx->data_pix_fmt == AV_PIX_FMT_YUV444P && ret <= 0) {
if (IS_YUV444(ctx->data_pix_fmt) && ret <= 0) {
av_log(avctx, AV_LOG_VERBOSE, "YUV444P not supported\n");
return AVERROR(ENOSYS);
}
@ -314,6 +322,12 @@ static int nvenc_check_capabilities(AVCodecContext *avctx)
return AVERROR(ENOSYS);
}
ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE);
if (IS_10BIT(ctx->data_pix_fmt) && ret <= 0) {
av_log(avctx, AV_LOG_VERBOSE, "10 bit encode not supported\n");
return AVERROR(ENOSYS);
}
return 0;
}
@ -800,9 +814,26 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx)
hevc->outputPictureTimingSEI = 1;
}
/* No other profile is supported in the current SDK version 5 */
cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID;
avctx->profile = FF_PROFILE_HEVC_MAIN;
switch(ctx->profile) {
case NV_ENC_HEVC_PROFILE_MAIN:
cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID;
avctx->profile = FF_PROFILE_HEVC_MAIN;
break;
case NV_ENC_HEVC_PROFILE_MAIN_10:
cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
avctx->profile = FF_PROFILE_HEVC_MAIN_10;
break;
}
// force setting profile as main10 if input is 10 bit
if (IS_10BIT(ctx->data_pix_fmt)) {
cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
avctx->profile = FF_PROFILE_HEVC_MAIN_10;
}
hevc->chromaFormatIDC = IS_YUV444(ctx->data_pix_fmt) ? 3 : 1;
hevc->pixelBitDepthMinus8 = IS_10BIT(ctx->data_pix_fmt) ? 2 : 0;
hevc->level = ctx->level;
@ -958,10 +989,18 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx)
ctx->surfaces[idx].format = NV_ENC_BUFFER_FORMAT_NV12_PL;
break;
case AV_PIX_FMT_P010:
ctx->surfaces[idx].format = NV_ENC_BUFFER_FORMAT_YUV420_10BIT;
break;
case AV_PIX_FMT_YUV444P:
ctx->surfaces[idx].format = NV_ENC_BUFFER_FORMAT_YUV444_PL;
break;
case AV_PIX_FMT_YUV444P16:
ctx->surfaces[idx].format = NV_ENC_BUFFER_FORMAT_YUV444_10BIT;
break;
default:
av_log(avctx, AV_LOG_FATAL, "Invalid input pixel format\n");
return AVERROR(EINVAL);
@ -1238,6 +1277,16 @@ static int nvenc_copy_frame(AVCodecContext *avctx, NvencSurface *inSurf,
av_image_copy_plane(buf, lockBufferParams->pitch,
frame->data[1], frame->linesize[1],
avctx->width, avctx->height >> 1);
} else if (frame->format == AV_PIX_FMT_P010) {
av_image_copy_plane(buf, lockBufferParams->pitch,
frame->data[0], frame->linesize[0],
avctx->width << 1, avctx->height);
buf += off;
av_image_copy_plane(buf, lockBufferParams->pitch,
frame->data[1], frame->linesize[1],
avctx->width << 1, avctx->height >> 1);
} else if (frame->format == AV_PIX_FMT_YUV444P) {
av_image_copy_plane(buf, lockBufferParams->pitch,
frame->data[0], frame->linesize[0],
@ -1254,6 +1303,22 @@ static int nvenc_copy_frame(AVCodecContext *avctx, NvencSurface *inSurf,
av_image_copy_plane(buf, lockBufferParams->pitch,
frame->data[2], frame->linesize[2],
avctx->width, avctx->height);
} else if (frame->format == AV_PIX_FMT_YUV444P16) {
av_image_copy_plane(buf, lockBufferParams->pitch,
frame->data[0], frame->linesize[0],
avctx->width << 1, avctx->height);
buf += off;
av_image_copy_plane(buf, lockBufferParams->pitch,
frame->data[1], frame->linesize[1],
avctx->width << 1, avctx->height);
buf += off;
av_image_copy_plane(buf, lockBufferParams->pitch,
frame->data[2], frame->linesize[2],
avctx->width << 1, avctx->height);
} else {
av_log(avctx, AV_LOG_FATAL, "Invalid pixel format!\n");
return AVERROR(EINVAL);

View File

@ -116,6 +116,11 @@ enum {
NV_ENC_H264_PROFILE_HIGH_444P,
};
enum {
NV_ENC_HEVC_PROFILE_MAIN,
NV_ENC_HEVC_PROFILE_MAIN_10,
};
enum {
NVENC_LOWLATENCY = 1,
NVENC_LOSSLESS = 2,

View File

@ -39,8 +39,9 @@ static const AVOption options[] = {
{ "llhp", "low latency hp", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_LOW_LATENCY_HP }, 0, 0, VE, "preset" },
{ "lossless", "lossless", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_LOSSLESS_DEFAULT }, 0, 0, VE, "preset" },
{ "losslesshp", "lossless hp", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_LOSSLESS_HP }, 0, 0, VE, "preset" },
{ "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = FF_PROFILE_HEVC_MAIN }, FF_PROFILE_HEVC_MAIN, FF_PROFILE_HEVC_MAIN, VE, "profile" },
{ "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_HEVC_MAIN }, 0, 0, VE, "profile" },
{ "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = NV_ENC_HEVC_PROFILE_MAIN }, NV_ENC_HEVC_PROFILE_MAIN, FF_PROFILE_HEVC_MAIN_10, VE, "profile" },
{ "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_MAIN }, 0, 0, VE, "profile" },
{ "main10", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_HEVC_PROFILE_MAIN_10 }, 0, 0, VE, "profile" },
{ "level", "Set the encoding level restriction", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = NV_ENC_LEVEL_AUTOSELECT }, NV_ENC_LEVEL_AUTOSELECT, NV_ENC_LEVEL_HEVC_62, VE, "level" },
{ "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LEVEL_AUTOSELECT }, 0, 0, VE, "level" },
{ "1", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LEVEL_HEVC_1 }, 0, 0, VE, "level" },

View File

@ -29,7 +29,7 @@
#define LIBAVCODEC_VERSION_MAJOR 57
#define LIBAVCODEC_VERSION_MINOR 54
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_MICRO 101
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \