summaryrefslogtreecommitdiff
path: root/libavcodec/nvdec.c
diff options
context:
space:
mode:
authorPhilip Langdale <philipl@overt.org>2018-10-06 18:11:52 -0700
committerPhilip Langdale <philipl@overt.org>2019-02-16 08:47:36 -0800
commite06ccfbe1d33c00d6f1df202a514219c7fdb7c03 (patch)
treec5c8e12daa938de6bab9bf1e1fe7a03a2093dc01 /libavcodec/nvdec.c
parentf4ea930a119298c6110ee4e3d24219a66e27e230 (diff)
downloadffmpeg-e06ccfbe1d33c00d6f1df202a514219c7fdb7c03.tar.gz
avcodec/nvdec: Add support for decoding HEVC 4:4:4 content
The latest generation video decoder on the Turing chips supports decoding HEVC 4:4:4. Supporting this is relatively straight-forward; we need to account for the different chroma format and pick the right output and sw formats at the right times. There was one bug which was the hard-coded assumption that the first chroma plane would be half-height; I fixed this to use the actual shift value on the plane. We also need to pass the SPS and PPS range extension flags.
Diffstat (limited to 'libavcodec/nvdec.c')
-rw-r--r--libavcodec/nvdec.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c
index c7d5379770..72201a1123 100644
--- a/libavcodec/nvdec.c
+++ b/libavcodec/nvdec.c
@@ -35,6 +35,11 @@
#include "nvdec.h"
#include "internal.h"
+#if !NVDECAPI_CHECK_VERSION(9, 0)
+#define cudaVideoSurfaceFormat_YUV444 2
+#define cudaVideoSurfaceFormat_YUV444_16Bit 3
+#endif
+
typedef struct NVDECDecoder {
CUvideodecoder decoder;
@@ -274,7 +279,8 @@ int ff_nvdec_decode_init(AVCodecContext *avctx)
CUVIDDECODECREATEINFO params = { 0 };
- int cuvid_codec_type, cuvid_chroma_format;
+ cudaVideoSurfaceFormat output_format;
+ int cuvid_codec_type, cuvid_chroma_format, chroma_444;
int ret = 0;
sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
@@ -292,6 +298,7 @@ int ff_nvdec_decode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR, "Unsupported chroma format\n");
return AVERROR(ENOSYS);
}
+ chroma_444 = cuvid_chroma_format == cudaVideoChromaFormat_444;
if (!avctx->hw_frames_ctx) {
ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_CUDA);
@@ -299,6 +306,21 @@ int ff_nvdec_decode_init(AVCodecContext *avctx)
return ret;
}
+ switch (sw_desc->comp[0].depth) {
+ case 8:
+ output_format = chroma_444 ? cudaVideoSurfaceFormat_YUV444 :
+ cudaVideoSurfaceFormat_NV12;
+ break;
+ case 10:
+ case 12:
+ output_format = chroma_444 ? cudaVideoSurfaceFormat_YUV444_16Bit :
+ cudaVideoSurfaceFormat_P016;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth\n");
+ return AVERROR(ENOSYS);
+ }
+
frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
params.ulWidth = avctx->coded_width;
@@ -306,8 +328,7 @@ int ff_nvdec_decode_init(AVCodecContext *avctx)
params.ulTargetWidth = avctx->coded_width;
params.ulTargetHeight = avctx->coded_height;
params.bitDepthMinus8 = sw_desc->comp[0].depth - 8;
- params.OutputFormat = params.bitDepthMinus8 ?
- cudaVideoSurfaceFormat_P016 : cudaVideoSurfaceFormat_NV12;
+ params.OutputFormat = output_format;
params.CodecType = cuvid_codec_type;
params.ChromaFormat = cuvid_chroma_format;
params.ulNumDecodeSurfaces = frames_ctx->initial_pool_size;
@@ -386,6 +407,8 @@ static int nvdec_retrieve_data(void *logctx, AVFrame *frame)
NVDECFrame *cf = (NVDECFrame*)fdd->hwaccel_priv;
NVDECDecoder *decoder = (NVDECDecoder*)cf->decoder_ref->data;
+ AVHWFramesContext *hwctx = (AVHWFramesContext *)frame->hw_frames_ctx->data;
+
CUVIDPROCPARAMS vpp = { 0 };
NVDECFrame *unmap_data = NULL;
@@ -394,6 +417,7 @@ static int nvdec_retrieve_data(void *logctx, AVFrame *frame)
unsigned int pitch, i;
unsigned int offset = 0;
+ int shift_h = 0, shift_v = 0;
int ret = 0;
vpp.progressive_frame = 1;
@@ -427,10 +451,11 @@ static int nvdec_retrieve_data(void *logctx, AVFrame *frame)
unmap_data->idx_ref = av_buffer_ref(cf->idx_ref);
unmap_data->decoder_ref = av_buffer_ref(cf->decoder_ref);
+ av_pix_fmt_get_chroma_sub_sample(hwctx->sw_format, &shift_h, &shift_v);
for (i = 0; frame->linesize[i]; i++) {
frame->data[i] = (uint8_t*)(devptr + offset);
frame->linesize[i] = pitch;
- offset += pitch * (frame->height >> (i ? 1 : 0));
+ offset += pitch * (frame->height >> (i ? shift_v : 0));
}
goto finish;
@@ -566,7 +591,7 @@ int ff_nvdec_frame_params(AVCodecContext *avctx,
{
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data;
const AVPixFmtDescriptor *sw_desc;
- int cuvid_codec_type, cuvid_chroma_format;
+ int cuvid_codec_type, cuvid_chroma_format, chroma_444;
sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
if (!sw_desc)
@@ -583,6 +608,7 @@ int ff_nvdec_frame_params(AVCodecContext *avctx,
av_log(avctx, AV_LOG_VERBOSE, "Unsupported chroma format\n");
return AVERROR(EINVAL);
}
+ chroma_444 = cuvid_chroma_format == cudaVideoChromaFormat_444;
frames_ctx->format = AV_PIX_FMT_CUDA;
frames_ctx->width = (avctx->coded_width + 1) & ~1;
@@ -601,13 +627,13 @@ int ff_nvdec_frame_params(AVCodecContext *avctx,
switch (sw_desc->comp[0].depth) {
case 8:
- frames_ctx->sw_format = AV_PIX_FMT_NV12;
+ frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12;
break;
case 10:
- frames_ctx->sw_format = AV_PIX_FMT_P010;
+ frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010;
break;
case 12:
- frames_ctx->sw_format = AV_PIX_FMT_P016;
+ frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016;
break;
default:
return AVERROR(EINVAL);