X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fcuvid.c;h=2ba8e00c6af1f923858f5215f553e0b565e10f08;hb=f386dd70acdc81d42d6bcb885d2889634cdf45b7;hp=288083423ebbf51b9d4f9861101a4f5d09398265;hpb=8c6f18e4449ad2bb3c30621b9dca45acc86332cb;p=ffmpeg diff --git a/libavcodec/cuvid.c b/libavcodec/cuvid.c index 288083423eb..2ba8e00c6af 100644 --- a/libavcodec/cuvid.c +++ b/libavcodec/cuvid.c @@ -76,6 +76,8 @@ typedef struct CuvidContext cudaVideoCodec codec_type; cudaVideoChromaFormat chroma_format; + CUVIDDECODECAPS caps8, caps10, caps12; + CUVIDPARSERPARAMS cuparseinfo; CUVIDEOFORMATEX cuparse_ext; @@ -119,6 +121,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form AVCodecContext *avctx = opaque; CuvidContext *ctx = avctx->priv_data; AVHWFramesContext *hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data; + CUVIDDECODECAPS *caps = NULL; CUVIDDECODECREATEINFO cuinfo; int surface_fmt; @@ -166,19 +169,27 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form switch (format->bit_depth_luma_minus8) { case 0: // 8-bit pix_fmts[1] = AV_PIX_FMT_NV12; + caps = &ctx->caps8; break; case 2: // 10-bit pix_fmts[1] = AV_PIX_FMT_P010; + caps = &ctx->caps10; break; case 4: // 12-bit pix_fmts[1] = AV_PIX_FMT_P016; + caps = &ctx->caps12; break; default: + break; + } + + if (!caps || !caps->bIsSupported) { av_log(avctx, AV_LOG_ERROR, "unsupported bit depth: %d\n", format->bit_depth_luma_minus8 + 8); ctx->internal_error = AVERROR(EINVAL); return 0; } + surface_fmt = ff_get_format(avctx, pix_fmts); if (surface_fmt < 0) { av_log(avctx, AV_LOG_ERROR, "ff_get_format failed: %d\n", surface_fmt); @@ -686,46 +697,90 @@ static av_cold int cuvid_decode_end(AVCodecContext *avctx) return 0; } -static int cuvid_test_dummy_decoder(AVCodecContext *avctx, - const CUVIDPARSERPARAMS *cuparseinfo, - int probed_width, - int probed_height) +static int cuvid_test_capabilities(AVCodecContext *avctx, + const CUVIDPARSERPARAMS *cuparseinfo, + int probed_width, + int probed_height, + int bit_depth) { CuvidContext *ctx = avctx->priv_data; - CUVIDDECODECREATEINFO cuinfo; - CUvideodecoder cudec = 0; - int ret = 0; - - memset(&cuinfo, 0, sizeof(cuinfo)); - - cuinfo.CodecType = cuparseinfo->CodecType; - cuinfo.ChromaFormat = cudaVideoChromaFormat_420; - cuinfo.OutputFormat = cudaVideoSurfaceFormat_NV12; - - cuinfo.ulWidth = probed_width; - cuinfo.ulHeight = probed_height; - cuinfo.ulTargetWidth = cuinfo.ulWidth; - cuinfo.ulTargetHeight = cuinfo.ulHeight; + CUVIDDECODECAPS *caps; + int res8 = 0, res10 = 0, res12 = 0; + + if (!ctx->cvdl->cuvidGetDecoderCaps) { + av_log(avctx, AV_LOG_WARNING, "Used Nvidia driver is too old to perform a capability check.\n"); + av_log(avctx, AV_LOG_WARNING, "The minimum required version is " +#if defined(_WIN32) || defined(__CYGWIN__) + "378.66" +#else + "378.13" +#endif + ". Continuing blind.\n"); + ctx->caps8.bIsSupported = ctx->caps10.bIsSupported = 1; + // 12 bit was not supported before the capability check was introduced, so disable it. + ctx->caps12.bIsSupported = 0; + return 0; + } - cuinfo.target_rect.left = 0; - cuinfo.target_rect.top = 0; - cuinfo.target_rect.right = cuinfo.ulWidth; - cuinfo.target_rect.bottom = cuinfo.ulHeight; + ctx->caps8.eCodecType = ctx->caps10.eCodecType = ctx->caps12.eCodecType + = cuparseinfo->CodecType; + ctx->caps8.eChromaFormat = ctx->caps10.eChromaFormat = ctx->caps12.eChromaFormat + = cudaVideoChromaFormat_420; + + ctx->caps8.nBitDepthMinus8 = 0; + ctx->caps10.nBitDepthMinus8 = 2; + ctx->caps12.nBitDepthMinus8 = 4; + + res8 = CHECK_CU(ctx->cvdl->cuvidGetDecoderCaps(&ctx->caps8)); + res10 = CHECK_CU(ctx->cvdl->cuvidGetDecoderCaps(&ctx->caps10)); + res12 = CHECK_CU(ctx->cvdl->cuvidGetDecoderCaps(&ctx->caps12)); + + av_log(avctx, AV_LOG_VERBOSE, "CUVID capabilities for %s:\n", avctx->codec->name); + av_log(avctx, AV_LOG_VERBOSE, "8 bit: supported: %d, min_width: %d, max_width: %d, min_height: %d, max_height: %d\n", + ctx->caps8.bIsSupported, ctx->caps8.nMinWidth, ctx->caps8.nMaxWidth, ctx->caps8.nMinHeight, ctx->caps8.nMaxHeight); + av_log(avctx, AV_LOG_VERBOSE, "10 bit: supported: %d, min_width: %d, max_width: %d, min_height: %d, max_height: %d\n", + ctx->caps10.bIsSupported, ctx->caps10.nMinWidth, ctx->caps10.nMaxWidth, ctx->caps10.nMinHeight, ctx->caps10.nMaxHeight); + av_log(avctx, AV_LOG_VERBOSE, "12 bit: supported: %d, min_width: %d, max_width: %d, min_height: %d, max_height: %d\n", + ctx->caps12.bIsSupported, ctx->caps12.nMinWidth, ctx->caps12.nMaxWidth, ctx->caps12.nMinHeight, ctx->caps12.nMaxHeight); + + switch (bit_depth) { + case 10: + caps = &ctx->caps10; + if (res10 < 0) + return res10; + break; + case 12: + caps = &ctx->caps12; + if (res12 < 0) + return res12; + break; + default: + caps = &ctx->caps8; + if (res8 < 0) + return res8; + } - cuinfo.ulNumDecodeSurfaces = ctx->nb_surfaces; - cuinfo.ulNumOutputSurfaces = 1; - cuinfo.ulCreationFlags = cudaVideoCreate_PreferCUVID; - cuinfo.bitDepthMinus8 = 0; + if (!ctx->caps8.bIsSupported) { + av_log(avctx, AV_LOG_ERROR, "Codec %s is not supported.\n", avctx->codec->name); + return AVERROR(EINVAL); + } - cuinfo.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave; + if (!caps->bIsSupported) { + av_log(avctx, AV_LOG_ERROR, "Bit depth %d is not supported.\n", bit_depth); + return AVERROR(EINVAL); + } - ret = CHECK_CU(ctx->cvdl->cuvidCreateDecoder(&cudec, &cuinfo)); - if (ret < 0) - return ret; + if (probed_width > caps->nMaxWidth || probed_width < caps->nMinWidth) { + av_log(avctx, AV_LOG_ERROR, "Video width %d not within range from %d to %d\n", + probed_width, caps->nMinWidth, caps->nMaxWidth); + return AVERROR(EINVAL); + } - ret = CHECK_CU(ctx->cvdl->cuvidDestroyDecoder(cudec)); - if (ret < 0) - return ret; + if (probed_height > caps->nMaxHeight || probed_height < caps->nMinHeight) { + av_log(avctx, AV_LOG_ERROR, "Video height %d not within range from %d to %d\n", + probed_height, caps->nMinHeight, caps->nMaxHeight); + return AVERROR(EINVAL); + } return 0; } @@ -748,6 +803,11 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) int probed_width = avctx->coded_width ? avctx->coded_width : 1280; int probed_height = avctx->coded_height ? avctx->coded_height : 720; + int probed_bit_depth = 8; + + const AVPixFmtDescriptor *probe_desc = av_pix_fmt_desc_get(avctx->pix_fmt); + if (probe_desc && probe_desc->nb_components) + probed_bit_depth = probe_desc->comp[0].depth; // Accelerated transcoding scenarios with 'ffmpeg' require that the // pix_fmt be set to AV_PIX_FMT_CUDA early. The sw_pix_fmt, and the @@ -802,9 +862,17 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) goto error; } } else { - ret = av_hwdevice_ctx_create(&ctx->hwdevice, AV_HWDEVICE_TYPE_CUDA, ctx->cu_gpu, NULL, 0); - if (ret < 0) - goto error; + if (avctx->hw_device_ctx) { + ctx->hwdevice = av_buffer_ref(avctx->hw_device_ctx); + if (!ctx->hwdevice) { + ret = AVERROR(ENOMEM); + goto error; + } + } else { + ret = av_hwdevice_ctx_create(&ctx->hwdevice, AV_HWDEVICE_TYPE_CUDA, ctx->cu_gpu, NULL, 0); + if (ret < 0) + goto error; + } ctx->hwframe = av_hwframe_ctx_alloc(ctx->hwdevice); if (!ctx->hwframe) { @@ -919,9 +987,10 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) if (ret < 0) goto error; - ret = cuvid_test_dummy_decoder(avctx, &ctx->cuparseinfo, - probed_width, - probed_height); + ret = cuvid_test_capabilities(avctx, &ctx->cuparseinfo, + probed_width, + probed_height, + probed_bit_depth); if (ret < 0) goto error;