aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec/nvdec.c
diff options
context:
space:
mode:
authorTimo Rothenpieler <timo@rothenpieler.org>2017-11-11 16:08:53 +0100
committerTimo Rothenpieler <timo@rothenpieler.org>2017-11-12 15:46:39 +0100
commitc60bc02bf4bc4f6f57fd0fd4c5b2e63253623185 (patch)
treebc59c1032381e8f6881afaae955ffe49bd36e532 /libavcodec/nvdec.c
parent3e0e1634585b1a26b7d753aa42c7f350636927ae (diff)
downloadffmpeg-c60bc02bf4bc4f6f57fd0fd4c5b2e63253623185.tar.gz
avcodec/nvdec: check hardware capabilities
Diffstat (limited to 'libavcodec/nvdec.c')
-rw-r--r--libavcodec/nvdec.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c
index 58ebeeb9c1..6287897343 100644
--- a/libavcodec/nvdec.c
+++ b/libavcodec/nvdec.c
@@ -74,6 +74,56 @@ static int map_chroma_format(enum AVPixelFormat pix_fmt)
return -1;
}
+static int nvdec_test_capabilities(NVDECDecoder *decoder,
+ CUVIDDECODECREATEINFO *params, void *logctx)
+{
+ CUresult err;
+ CUVIDDECODECAPS caps = { 0 };
+
+ caps.eCodecType = params->CodecType;
+ caps.eChromaFormat = params->ChromaFormat;
+ caps.nBitDepthMinus8 = params->bitDepthMinus8;
+
+ err = decoder->cvdl->cuvidGetDecoderCaps(&caps);
+ if (err != CUDA_SUCCESS) {
+ av_log(logctx, AV_LOG_ERROR, "Failed querying decoder capabilities\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ av_log(logctx, AV_LOG_VERBOSE, "NVDEC capabilities:\n");
+ av_log(logctx, AV_LOG_VERBOSE, "format supported: %s, max_mb_count: %d\n",
+ caps.bIsSupported ? "yes" : "no", caps.nMaxMBCount);
+ av_log(logctx, AV_LOG_VERBOSE, "min_width: %d, max_width: %d\n",
+ caps.nMinWidth, caps.nMaxWidth);
+ av_log(logctx, AV_LOG_VERBOSE, "min_height: %d, max_height: %d\n",
+ caps.nMinHeight, caps.nMaxHeight);
+
+ if (!caps.bIsSupported) {
+ av_log(logctx, AV_LOG_ERROR, "Hardware is lacking required capabilities\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (params->ulWidth > caps.nMaxWidth || params->ulWidth < caps.nMinWidth) {
+ av_log(logctx, AV_LOG_ERROR, "Video width %d not within range from %d to %d\n",
+ (int)params->ulWidth, caps.nMinWidth, caps.nMaxWidth);
+ return AVERROR(EINVAL);
+ }
+
+ if (params->ulHeight > caps.nMaxHeight || params->ulHeight < caps.nMinHeight) {
+ av_log(logctx, AV_LOG_ERROR, "Video height %d not within range from %d to %d\n",
+ (int)params->ulHeight, caps.nMinHeight, caps.nMaxHeight);
+ return AVERROR(EINVAL);
+ }
+
+ if ((params->ulWidth * params->ulHeight) / 256 > caps.nMaxMBCount) {
+ av_log(logctx, AV_LOG_ERROR, "Video macroblock count %d exceeds maximum of %d\n",
+ (int)(params->ulWidth * params->ulHeight) / 256, caps.nMaxMBCount);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
static void nvdec_decoder_free(void *opaque, uint8_t *data)
{
NVDECDecoder *decoder = (NVDECDecoder*)data;
@@ -132,6 +182,12 @@ static int nvdec_decoder_create(AVBufferRef **out, AVBufferRef *hw_device_ref,
goto fail;
}
+ ret = nvdec_test_capabilities(decoder, params, logctx);
+ if (ret < 0) {
+ decoder->cudl->cuCtxPopCurrent(&dummy);
+ goto fail;
+ }
+
err = decoder->cvdl->cuvidCreateDecoder(&decoder->decoder, params);
decoder->cudl->cuCtxPopCurrent(&dummy);