early-access version 1680
This commit is contained in:
197
externals/ffmpeg/libavcodec/nvenc.c
vendored
197
externals/ffmpeg/libavcodec/nvenc.c
vendored
@@ -22,6 +22,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "nvenc.h"
|
||||
#include "hevc_sei.h"
|
||||
|
||||
#include "libavutil/hwcontext_cuda.h"
|
||||
#include "libavutil/hwcontext.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "encode.h"
|
||||
#include "internal.h"
|
||||
#include "packet_internal.h"
|
||||
|
||||
@@ -40,6 +42,12 @@
|
||||
rc == NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ || \
|
||||
rc == NV_ENC_PARAMS_RC_CBR_HQ)
|
||||
|
||||
#ifdef NVENC_HAVE_NEW_PRESETS
|
||||
#define IS_SDK10_PRESET(p) ((p) >= PRESET_P1 && (p) <= PRESET_P7)
|
||||
#else
|
||||
#define IS_SDK10_PRESET(p) 0
|
||||
#endif
|
||||
|
||||
const enum AVPixelFormat ff_nvenc_pix_fmts[] = {
|
||||
AV_PIX_FMT_YUV420P,
|
||||
AV_PIX_FMT_NV12,
|
||||
@@ -143,8 +151,14 @@ static int nvenc_print_error(AVCodecContext *avctx, NVENCSTATUS err,
|
||||
|
||||
static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level)
|
||||
{
|
||||
#if NVENCAPI_CHECK_VERSION(9, 2)
|
||||
#if NVENCAPI_CHECK_VERSION(10, 1)
|
||||
const char *minver = "(unknown)";
|
||||
#elif NVENCAPI_CHECK_VERSION(10, 0)
|
||||
# if defined(_WIN32) || defined(__CYGWIN__)
|
||||
const char *minver = "450.51";
|
||||
# else
|
||||
const char *minver = "445.87";
|
||||
# endif
|
||||
#elif NVENCAPI_CHECK_VERSION(9, 1)
|
||||
# if defined(_WIN32) || defined(__CYGWIN__)
|
||||
const char *minver = "436.15";
|
||||
@@ -648,6 +662,15 @@ static void nvenc_map_preset(NvencContext *ctx)
|
||||
PRESET(LOW_LATENCY_HQ, NVENC_LOWLATENCY),
|
||||
PRESET(LOSSLESS_DEFAULT, NVENC_LOSSLESS),
|
||||
PRESET(LOSSLESS_HP, NVENC_LOSSLESS),
|
||||
#ifdef NVENC_HAVE_NEW_PRESETS
|
||||
PRESET(P1),
|
||||
PRESET(P2),
|
||||
PRESET(P3),
|
||||
PRESET(P4),
|
||||
PRESET(P5),
|
||||
PRESET(P6),
|
||||
PRESET(P7),
|
||||
#endif
|
||||
};
|
||||
|
||||
GUIDTuple *t = &presets[ctx->preset];
|
||||
@@ -857,6 +880,12 @@ static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx)
|
||||
if (avctx->rc_max_rate > 0)
|
||||
ctx->encode_config.rcParams.maxBitRate = avctx->rc_max_rate;
|
||||
|
||||
#ifdef NVENC_HAVE_MULTIPASS
|
||||
ctx->encode_config.rcParams.multiPass = ctx->multipass;
|
||||
if (ctx->encode_config.rcParams.multiPass != NV_ENC_MULTI_PASS_DISABLED)
|
||||
ctx->flags |= NVENC_TWO_PASSES;
|
||||
#endif
|
||||
|
||||
if (ctx->rc < 0) {
|
||||
if (ctx->flags & NVENC_ONE_PASS)
|
||||
ctx->twopass = 0;
|
||||
@@ -891,6 +920,11 @@ static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx)
|
||||
ctx->rc &= ~RC_MODE_DEPRECATED;
|
||||
}
|
||||
|
||||
#ifdef NVENC_HAVE_LDKFS
|
||||
if (ctx->ldkfs)
|
||||
ctx->encode_config.rcParams.lowDelayKeyFrameScale = ctx->ldkfs;
|
||||
#endif
|
||||
|
||||
if (ctx->flags & NVENC_LOSSLESS) {
|
||||
set_lossless(avctx);
|
||||
} else if (ctx->rc >= 0) {
|
||||
@@ -1200,10 +1234,27 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
|
||||
preset_config.version = NV_ENC_PRESET_CONFIG_VER;
|
||||
preset_config.presetCfg.version = NV_ENC_CONFIG_VER;
|
||||
|
||||
nv_status = p_nvenc->nvEncGetEncodePresetConfig(ctx->nvencoder,
|
||||
ctx->init_encode_params.encodeGUID,
|
||||
ctx->init_encode_params.presetGUID,
|
||||
&preset_config);
|
||||
if (IS_SDK10_PRESET(ctx->preset)) {
|
||||
#ifdef NVENC_HAVE_NEW_PRESETS
|
||||
ctx->init_encode_params.tuningInfo = ctx->tuning_info;
|
||||
|
||||
nv_status = p_nvenc->nvEncGetEncodePresetConfigEx(ctx->nvencoder,
|
||||
ctx->init_encode_params.encodeGUID,
|
||||
ctx->init_encode_params.presetGUID,
|
||||
ctx->init_encode_params.tuningInfo,
|
||||
&preset_config);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef NVENC_HAVE_NEW_PRESETS
|
||||
// Turn off tuning info parameter if older presets are on
|
||||
ctx->init_encode_params.tuningInfo = 0;
|
||||
#endif
|
||||
|
||||
nv_status = p_nvenc->nvEncGetEncodePresetConfig(ctx->nvencoder,
|
||||
ctx->init_encode_params.encodeGUID,
|
||||
ctx->init_encode_params.presetGUID,
|
||||
&preset_config);
|
||||
}
|
||||
if (nv_status != NV_ENC_SUCCESS)
|
||||
return nvenc_print_error(avctx, nv_status, "Cannot get the preset configuration");
|
||||
|
||||
@@ -1226,6 +1277,17 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
|
||||
ctx->init_encode_params.enableEncodeAsync = 0;
|
||||
ctx->init_encode_params.enablePTD = 1;
|
||||
|
||||
#ifdef NVENC_HAVE_NEW_PRESETS
|
||||
/* If lookahead isn't set from CLI, use value from preset.
|
||||
* P6 & P7 presets may enable lookahead for better quality.
|
||||
* */
|
||||
if (ctx->rc_lookahead == 0 && ctx->encode_config.rcParams.enableLookahead)
|
||||
ctx->rc_lookahead = ctx->encode_config.rcParams.lookaheadDepth;
|
||||
|
||||
if (ctx->init_encode_params.tuningInfo == NV_ENC_TUNING_INFO_LOSSLESS)
|
||||
ctx->flags |= NVENC_LOSSLESS;
|
||||
#endif
|
||||
|
||||
if (ctx->weighted_pred == 1)
|
||||
ctx->init_encode_params.enableWeightedPrediction = 1;
|
||||
|
||||
@@ -1509,6 +1571,8 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
|
||||
av_freep(&ctx->surfaces);
|
||||
ctx->nb_surfaces = 0;
|
||||
|
||||
av_frame_free(&ctx->frame);
|
||||
|
||||
if (ctx->nvencoder) {
|
||||
p_nvenc->nvEncDestroyEncoder(ctx->nvencoder);
|
||||
|
||||
@@ -1562,6 +1626,10 @@ av_cold int ff_nvenc_encode_init(AVCodecContext *avctx)
|
||||
ctx->data_pix_fmt = avctx->pix_fmt;
|
||||
}
|
||||
|
||||
ctx->frame = av_frame_alloc();
|
||||
if (!ctx->frame)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
if ((ret = nvenc_load_libraries(avctx)) < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1776,7 +1844,8 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame,
|
||||
|
||||
static void nvenc_codec_specific_pic_params(AVCodecContext *avctx,
|
||||
NV_ENC_PIC_PARAMS *params,
|
||||
NV_ENC_SEI_PAYLOAD *sei_data)
|
||||
NV_ENC_SEI_PAYLOAD *sei_data,
|
||||
int sei_count)
|
||||
{
|
||||
NvencContext *ctx = avctx->priv_data;
|
||||
|
||||
@@ -1786,9 +1855,9 @@ static void nvenc_codec_specific_pic_params(AVCodecContext *avctx,
|
||||
ctx->encode_config.encodeCodecConfig.h264Config.sliceMode;
|
||||
params->codecPicParams.h264PicParams.sliceModeData =
|
||||
ctx->encode_config.encodeCodecConfig.h264Config.sliceModeData;
|
||||
if (sei_data) {
|
||||
if (sei_count > 0) {
|
||||
params->codecPicParams.h264PicParams.seiPayloadArray = sei_data;
|
||||
params->codecPicParams.h264PicParams.seiPayloadArrayCnt = 1;
|
||||
params->codecPicParams.h264PicParams.seiPayloadArrayCnt = sei_count;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1797,9 +1866,9 @@ static void nvenc_codec_specific_pic_params(AVCodecContext *avctx,
|
||||
ctx->encode_config.encodeCodecConfig.hevcConfig.sliceMode;
|
||||
params->codecPicParams.hevcPicParams.sliceModeData =
|
||||
ctx->encode_config.encodeCodecConfig.hevcConfig.sliceModeData;
|
||||
if (sei_data) {
|
||||
if (sei_count > 0) {
|
||||
params->codecPicParams.hevcPicParams.seiPayloadArray = sei_data;
|
||||
params->codecPicParams.hevcPicParams.seiPayloadArrayCnt = 1;
|
||||
params->codecPicParams.hevcPicParams.seiPayloadArrayCnt = sei_count;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1879,9 +1948,7 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur
|
||||
goto error;
|
||||
}
|
||||
|
||||
res = pkt->data ?
|
||||
ff_alloc_packet2(avctx, pkt, lock_params.bitstreamSizeInBytes, lock_params.bitstreamSizeInBytes) :
|
||||
av_new_packet(pkt, lock_params.bitstreamSizeInBytes);
|
||||
res = av_new_packet(pkt, lock_params.bitstreamSizeInBytes);
|
||||
|
||||
if (res < 0) {
|
||||
p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
|
||||
@@ -2067,13 +2134,14 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
|
||||
}
|
||||
}
|
||||
|
||||
int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
|
||||
static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
|
||||
{
|
||||
NVENCSTATUS nv_status;
|
||||
NvencSurface *tmp_out_surf, *in_surf;
|
||||
int res, res2;
|
||||
NV_ENC_SEI_PAYLOAD *sei_data = NULL;
|
||||
size_t sei_size;
|
||||
NV_ENC_SEI_PAYLOAD sei_data[8];
|
||||
int sei_count = 0;
|
||||
int i;
|
||||
|
||||
NvencContext *ctx = avctx->priv_data;
|
||||
NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
|
||||
@@ -2085,15 +2153,7 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
|
||||
if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
if (ctx->encoder_flushing) {
|
||||
if (avctx->internal->draining)
|
||||
return AVERROR_EOF;
|
||||
|
||||
ctx->encoder_flushing = 0;
|
||||
av_fifo_reset(ctx->timestamp_list);
|
||||
}
|
||||
|
||||
if (frame) {
|
||||
if (frame && frame->buf[0]) {
|
||||
in_surf = get_free_frame(ctx);
|
||||
if (!in_surf)
|
||||
return AVERROR(EAGAIN);
|
||||
@@ -2139,21 +2199,40 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
|
||||
pic_params.inputTimeStamp = frame->pts;
|
||||
|
||||
if (ctx->a53_cc && av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC)) {
|
||||
if (ff_alloc_a53_sei(frame, sizeof(NV_ENC_SEI_PAYLOAD), (void**)&sei_data, &sei_size) < 0) {
|
||||
void *a53_data = NULL;
|
||||
size_t a53_size = 0;
|
||||
|
||||
if (ff_alloc_a53_sei(frame, 0, (void**)&a53_data, &a53_size) < 0) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Not enough memory for closed captions, skipping\n");
|
||||
}
|
||||
|
||||
if (sei_data) {
|
||||
sei_data->payloadSize = (uint32_t)sei_size;
|
||||
sei_data->payloadType = 4;
|
||||
sei_data->payload = (uint8_t*)(sei_data + 1);
|
||||
if (a53_data) {
|
||||
sei_data[sei_count].payloadSize = (uint32_t)a53_size;
|
||||
sei_data[sei_count].payloadType = 4;
|
||||
sei_data[sei_count].payload = (uint8_t*)a53_data;
|
||||
sei_count ++;
|
||||
}
|
||||
}
|
||||
|
||||
nvenc_codec_specific_pic_params(avctx, &pic_params, sei_data);
|
||||
if (ctx->s12m_tc && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) {
|
||||
void *tc_data = NULL;
|
||||
size_t tc_size = 0;
|
||||
|
||||
if (ff_alloc_timecode_sei(frame, 0, (void**)&tc_data, &tc_size) < 0) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Not enough memory for timecode sei, skipping\n");
|
||||
}
|
||||
|
||||
if (tc_data) {
|
||||
sei_data[sei_count].payloadSize = (uint32_t)tc_size;
|
||||
sei_data[sei_count].payloadType = HEVC_SEI_TYPE_TIME_CODE;
|
||||
sei_data[sei_count].payload = (uint8_t*)tc_data;
|
||||
sei_count ++;
|
||||
}
|
||||
}
|
||||
|
||||
nvenc_codec_specific_pic_params(avctx, &pic_params, sei_data, sei_count);
|
||||
} else {
|
||||
pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
|
||||
ctx->encoder_flushing = 1;
|
||||
}
|
||||
|
||||
res = nvenc_push_context(avctx);
|
||||
@@ -2161,7 +2240,9 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
|
||||
return res;
|
||||
|
||||
nv_status = p_nvenc->nvEncEncodePicture(ctx->nvencoder, &pic_params);
|
||||
av_free(sei_data);
|
||||
|
||||
for ( i = 0; i < sei_count; i++)
|
||||
av_freep(&sei_data[i].payload);
|
||||
|
||||
res = nvenc_pop_context(avctx);
|
||||
if (res < 0)
|
||||
@@ -2171,7 +2252,7 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
|
||||
nv_status != NV_ENC_ERR_NEED_MORE_INPUT)
|
||||
return nvenc_print_error(avctx, nv_status, "EncodePicture failed!");
|
||||
|
||||
if (frame) {
|
||||
if (frame && frame->buf[0]) {
|
||||
av_fifo_generic_write(ctx->output_surface_queue, &in_surf, sizeof(in_surf), NULL);
|
||||
timestamp_queue_enqueue(ctx->timestamp_list, frame->pts);
|
||||
}
|
||||
@@ -2194,10 +2275,25 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
|
||||
|
||||
NvencContext *ctx = avctx->priv_data;
|
||||
|
||||
AVFrame *frame = ctx->frame;
|
||||
|
||||
if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
if (output_ready(avctx, ctx->encoder_flushing)) {
|
||||
if (!frame->buf[0]) {
|
||||
res = ff_encode_get_frame(avctx, frame);
|
||||
if (res < 0 && res != AVERROR_EOF)
|
||||
return res;
|
||||
}
|
||||
|
||||
res = nvenc_send_frame(avctx, frame);
|
||||
if (res < 0) {
|
||||
if (res != AVERROR(EAGAIN))
|
||||
return res;
|
||||
} else
|
||||
av_frame_unref(frame);
|
||||
|
||||
if (output_ready(avctx, avctx->internal->draining)) {
|
||||
av_fifo_generic_read(ctx->output_surface_ready_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL);
|
||||
|
||||
res = nvenc_push_context(avctx);
|
||||
@@ -2214,7 +2310,7 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
|
||||
return res;
|
||||
|
||||
av_fifo_generic_write(ctx->unused_surface_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL);
|
||||
} else if (ctx->encoder_flushing) {
|
||||
} else if (avctx->internal->draining) {
|
||||
return AVERROR_EOF;
|
||||
} else {
|
||||
return AVERROR(EAGAIN);
|
||||
@@ -2223,31 +2319,10 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
|
||||
const AVFrame *frame, int *got_packet)
|
||||
{
|
||||
NvencContext *ctx = avctx->priv_data;
|
||||
int res;
|
||||
|
||||
if (!ctx->encoder_flushing) {
|
||||
res = ff_nvenc_send_frame(avctx, frame);
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
res = ff_nvenc_receive_packet(avctx, pkt);
|
||||
if (res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
|
||||
*got_packet = 0;
|
||||
} else if (res < 0) {
|
||||
return res;
|
||||
} else {
|
||||
*got_packet = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx)
|
||||
{
|
||||
ff_nvenc_send_frame(avctx, NULL);
|
||||
NvencContext *ctx = avctx->priv_data;
|
||||
|
||||
nvenc_send_frame(avctx, NULL);
|
||||
av_fifo_reset(ctx->timestamp_list);
|
||||
}
|
||||
|
Reference in New Issue
Block a user