X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fnvenc.c;h=9a96bf2bbafe5d0100a5c468742a46f76425ad8b;hb=56c8856966ecc7a016aa0edb5472a902a7fbd49a;hp=304a684e0c2816513a675ce4517a91a29621a7c8;hpb=5ca7eb36b7353f9e6af05a5a952eead5f6d326dd;p=ffmpeg diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 304a684e0c2..9a96bf2bbaf 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -110,19 +110,49 @@ static int nvenc_map_error(NVENCSTATUS err, const char **desc) return AVERROR_UNKNOWN; } -static int nvenc_print_error(void *log_ctx, NVENCSTATUS err, +static int nvenc_print_error(AVCodecContext *avctx, NVENCSTATUS err, const char *error_string) { const char *desc; - int ret; - ret = nvenc_map_error(err, &desc); - av_log(log_ctx, AV_LOG_ERROR, "%s: %s (%d)\n", error_string, desc, err); + const char *details = "(no details)"; + int ret = nvenc_map_error(err, &desc); + +#ifdef NVENC_HAVE_GETLASTERRORSTRING + NvencContext *ctx = avctx->priv_data; + NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &ctx->nvenc_dload_funcs.nvenc_funcs; + + if (p_nvenc && ctx->nvencoder) + details = p_nvenc->nvEncGetLastErrorString(ctx->nvencoder); +#endif + + av_log(avctx, AV_LOG_ERROR, "%s: %s (%d): %s\n", error_string, desc, err, details); + return ret; } static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) { -#if NVENCAPI_CHECK_VERSION(8, 1) +#if NVENCAPI_CHECK_VERSION(9, 2) + const char *minver = "(unknown)"; +#elif NVENCAPI_CHECK_VERSION(9, 1) +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "436.15"; +# else + const char *minver = "435.21"; +# endif +#elif NVENCAPI_CHECK_VERSION(9, 0) +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "418.81"; +# else + const char *minver = "418.30"; +# endif +#elif NVENCAPI_CHECK_VERSION(8, 2) +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "397.93"; +# else + const char *minver = "396.24"; +#endif +#elif NVENCAPI_CHECK_VERSION(8, 1) # if defined(_WIN32) || defined(__CYGWIN__) const char *minver = "390.77"; # else @@ -291,39 +321,39 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) ret = nvenc_check_codec_support(avctx); if (ret < 0) { - av_log(avctx, AV_LOG_VERBOSE, "Codec not supported\n"); + av_log(avctx, AV_LOG_WARNING, "Codec not supported\n"); return ret; } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_YUV444_ENCODE); if (IS_YUV444(ctx->data_pix_fmt) && ret <= 0) { - av_log(avctx, AV_LOG_VERBOSE, "YUV444P not supported\n"); + av_log(avctx, AV_LOG_WARNING, "YUV444P not supported\n"); return AVERROR(ENOSYS); } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE); if (ctx->preset >= PRESET_LOSSLESS_DEFAULT && ret <= 0) { - av_log(avctx, AV_LOG_VERBOSE, "Lossless encoding not supported\n"); + av_log(avctx, AV_LOG_WARNING, "Lossless encoding not supported\n"); return AVERROR(ENOSYS); } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_WIDTH_MAX); if (ret < avctx->width) { - av_log(avctx, AV_LOG_VERBOSE, "Width %d exceeds %d\n", + av_log(avctx, AV_LOG_WARNING, "Width %d exceeds %d\n", avctx->width, ret); return AVERROR(ENOSYS); } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_HEIGHT_MAX); if (ret < avctx->height) { - av_log(avctx, AV_LOG_VERBOSE, "Height %d exceeds %d\n", + av_log(avctx, AV_LOG_WARNING, "Height %d exceeds %d\n", avctx->height, ret); return AVERROR(ENOSYS); } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_NUM_MAX_BFRAMES); if (ret < avctx->max_b_frames) { - av_log(avctx, AV_LOG_VERBOSE, "Max B-frames %d exceed %d\n", + av_log(avctx, AV_LOG_WARNING, "Max B-frames %d exceed %d\n", avctx->max_b_frames, ret); return AVERROR(ENOSYS); @@ -331,7 +361,7 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_FIELD_ENCODING); if (ret < 1 && avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { - av_log(avctx, AV_LOG_VERBOSE, + av_log(avctx, AV_LOG_WARNING, "Interlaced encoding is not supported. Supported level: %d\n", ret); return AVERROR(ENOSYS); @@ -339,46 +369,59 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) 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"); + av_log(avctx, AV_LOG_WARNING, "10 bit encode not supported\n"); return AVERROR(ENOSYS); } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_LOOKAHEAD); if (ctx->rc_lookahead > 0 && ret <= 0) { - av_log(avctx, AV_LOG_VERBOSE, "RC lookahead not supported\n"); + av_log(avctx, AV_LOG_WARNING, "RC lookahead not supported\n"); return AVERROR(ENOSYS); } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ); if (ctx->temporal_aq > 0 && ret <= 0) { - av_log(avctx, AV_LOG_VERBOSE, "Temporal AQ not supported\n"); + av_log(avctx, AV_LOG_WARNING, "Temporal AQ not supported\n"); return AVERROR(ENOSYS); } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_WEIGHTED_PREDICTION); if (ctx->weighted_pred > 0 && ret <= 0) { - av_log (avctx, AV_LOG_VERBOSE, "Weighted Prediction not supported\n"); + av_log (avctx, AV_LOG_WARNING, "Weighted Prediction not supported\n"); return AVERROR(ENOSYS); } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_CABAC); if (ctx->coder == NV_ENC_H264_ENTROPY_CODING_MODE_CABAC && ret <= 0) { - av_log(avctx, AV_LOG_VERBOSE, "CABAC entropy coding not supported\n"); + av_log(avctx, AV_LOG_WARNING, "CABAC entropy coding not supported\n"); return AVERROR(ENOSYS); } #ifdef NVENC_HAVE_BFRAME_REF_MODE ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE); if (ctx->b_ref_mode == NV_ENC_BFRAME_REF_MODE_EACH && ret != 1) { - av_log(avctx, AV_LOG_VERBOSE, "Each B frame as reference is not supported\n"); + av_log(avctx, AV_LOG_WARNING, "Each B frame as reference is not supported\n"); return AVERROR(ENOSYS); } else if (ctx->b_ref_mode != NV_ENC_BFRAME_REF_MODE_DISABLED && ret == 0) { - av_log(avctx, AV_LOG_VERBOSE, "B frames as references are not supported\n"); + av_log(avctx, AV_LOG_WARNING, "B frames as references are not supported\n"); return AVERROR(ENOSYS); } #else if (ctx->b_ref_mode != 0) { - av_log(avctx, AV_LOG_VERBOSE, "B frames as references need SDK 8.1 at build time\n"); + av_log(avctx, AV_LOG_WARNING, "B frames as references need SDK 8.1 at build time\n"); + return AVERROR(ENOSYS); + } +#endif + +#ifdef NVENC_HAVE_MULTIPLE_REF_FRAMES + ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES); + if(avctx->refs != NV_ENC_NUM_REF_FRAMES_AUTOSELECT && ret <= 0) { + av_log(avctx, AV_LOG_WARNING, "Multiple reference frames are not supported by the device\n"); + return AVERROR(ENOSYS); + } +#else + if(avctx->refs != 0) { + av_log(avctx, AV_LOG_WARNING, "Multiple reference frames need SDK 9.1 at build time\n"); return AVERROR(ENOSYS); } #endif @@ -427,6 +470,7 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) goto fail; ctx->cu_context = ctx->cu_context_internal; + ctx->cu_stream = NULL; if ((ret = nvenc_pop_context(avctx)) < 0) goto fail2; @@ -513,6 +557,7 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) if (cuda_device_hwctx) { ctx->cu_context = cuda_device_hwctx->cuda_ctx; + ctx->cu_stream = cuda_device_hwctx->stream; } #if CONFIG_D3D11VA else if (d3d11_device_hwctx) { @@ -556,7 +601,7 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) return AVERROR_EXIT; if (!dl_fn->nvenc_device_count) { - av_log(avctx, AV_LOG_FATAL, "No NVENC capable devices found\n"); + av_log(avctx, AV_LOG_FATAL, "No capable devices found\n"); return AVERROR_EXTERNAL; } @@ -929,9 +974,9 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) h264->repeatSPSPPS = (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1; h264->outputAUD = ctx->aud; - if (avctx->refs >= 0) { + if (ctx->dpb_size >= 0) { /* 0 means "let the hardware decide" */ - h264->maxNumRefFrames = avctx->refs; + h264->maxNumRefFrames = ctx->dpb_size; } if (avctx->gop_size >= 0) { h264->idrPeriod = cc->gopLength; @@ -990,6 +1035,11 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) h264->useBFramesAsRef = ctx->b_ref_mode; #endif +#ifdef NVENC_HAVE_MULTIPLE_REF_FRAMES + h264->numRefL0 = avctx->refs; + h264->numRefL1 = avctx->refs; +#endif + return 0; } @@ -1021,9 +1071,9 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->repeatSPSPPS = (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1; hevc->outputAUD = ctx->aud; - if (avctx->refs >= 0) { + if (ctx->dpb_size >= 0) { /* 0 means "let the hardware decide" */ - hevc->maxNumRefFramesInDPB = avctx->refs; + hevc->maxNumRefFramesInDPB = ctx->dpb_size; } if (avctx->gop_size >= 0) { hevc->idrPeriod = cc->gopLength; @@ -1074,6 +1124,11 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->useBFramesAsRef = ctx->b_ref_mode; #endif +#ifdef NVENC_HAVE_MULTIPLE_REF_FRAMES + hevc->numRefL0 = avctx->refs; + hevc->numRefL1 = avctx->refs; +#endif + return 0; } @@ -1155,7 +1210,7 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) if (ctx->bluray_compat) { ctx->aud = 1; - avctx->refs = FFMIN(FFMAX(avctx->refs, 0), 6); + ctx->dpb_size = FFMIN(FFMAX(avctx->refs, 0), 6); avctx->max_b_frames = FFMIN(avctx->max_b_frames, 3); switch (avctx->codec->id) { case AV_CODEC_ID_H264: @@ -1202,15 +1257,25 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) return res; nv_status = p_nvenc->nvEncInitializeEncoder(ctx->nvencoder, &ctx->init_encode_params); + if (nv_status != NV_ENC_SUCCESS) { + nvenc_pop_context(avctx); + return nvenc_print_error(avctx, nv_status, "InitializeEncoder failed"); + } + +#ifdef NVENC_HAVE_CUSTREAM_PTR + if (ctx->cu_context) { + nv_status = p_nvenc->nvEncSetIOCudaStreams(ctx->nvencoder, &ctx->cu_stream, &ctx->cu_stream); + if (nv_status != NV_ENC_SUCCESS) { + nvenc_pop_context(avctx); + return nvenc_print_error(avctx, nv_status, "SetIOCudaStreams failed"); + } + } +#endif res = nvenc_pop_context(avctx); if (res < 0) return res; - if (nv_status != NV_ENC_SUCCESS) { - return nvenc_print_error(avctx, nv_status, "InitializeEncoder failed"); - } - if (ctx->encode_config.frameIntervalP > 1) avctx->has_b_frames = 2; @@ -1548,19 +1613,23 @@ static int nvenc_find_free_reg_resource(AVCodecContext *avctx) NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; NVENCSTATUS nv_status; - int i; + int i, first_round; if (ctx->nb_registered_frames == FF_ARRAY_ELEMS(ctx->registered_frames)) { - for (i = 0; i < ctx->nb_registered_frames; i++) { - if (!ctx->registered_frames[i].mapped) { - if (ctx->registered_frames[i].regptr) { - nv_status = p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[i].regptr); - if (nv_status != NV_ENC_SUCCESS) - return nvenc_print_error(avctx, nv_status, "Failed unregistering unused input resource"); - ctx->registered_frames[i].ptr = NULL; - ctx->registered_frames[i].regptr = NULL; + for (first_round = 1; first_round >= 0; first_round--) { + for (i = 0; i < ctx->nb_registered_frames; i++) { + if (!ctx->registered_frames[i].mapped) { + if (ctx->registered_frames[i].regptr) { + if (first_round) + continue; + nv_status = p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[i].regptr); + if (nv_status != NV_ENC_SUCCESS) + return nvenc_print_error(avctx, nv_status, "Failed unregistering unused input resource"); + ctx->registered_frames[i].ptr = NULL; + ctx->registered_frames[i].regptr = NULL; + } + return i; } - return i; } } } else { @@ -1812,7 +1881,11 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur goto error; } - if (res = ff_alloc_packet2(avctx, pkt, lock_params.bitstreamSizeInBytes,0)) { + res = pkt->data ? + ff_alloc_packet2(avctx, pkt, lock_params.bitstreamSizeInBytes, lock_params.bitstreamSizeInBytes) : + av_new_packet(pkt, lock_params.bitstreamSizeInBytes); + + if (res < 0) { p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface); goto error; } @@ -1834,13 +1907,6 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur res = nvenc_print_error(avctx, nv_status, "Failed unmapping input resource"); goto error; } - nv_status = p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[tmpoutsurf->reg_idx].regptr); - if (nv_status != NV_ENC_SUCCESS) { - res = nvenc_print_error(avctx, nv_status, "Failed unregistering input resource"); - goto error; - } - ctx->registered_frames[tmpoutsurf->reg_idx].ptr = NULL; - ctx->registered_frames[tmpoutsurf->reg_idx].regptr = NULL; } else if (ctx->registered_frames[tmpoutsurf->reg_idx].mapped < 0) { res = AVERROR_BUG; goto error; @@ -2196,3 +2262,8 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } + +av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx) +{ + ff_nvenc_send_frame(avctx, NULL); +}