mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
avcodec/cuvid: Add support for P010/P016 as an output surface format
The nvidia 375.xx driver introduces support for P016 output surfaces, for 10bit and 12bit HEVC content (it's also the first driver to support hardware decoding of 12bit content). The cuvid api, as far as I can tell, only declares one output format that they appear to refer to as P016 in the driver strings. Of course, 10bit content in P016 is identical to P010, and it is useful for compatibility purposes to declare the format to be P010 to work with other components that only know how to consume P010 (and to avoid triggering swscale conversions that are lossy when they shouldn't be). For simplicity, this change does not maintain the previous ability to output dithered NV12 for 10/12 bit input video - the user will need to update their driver to decode such videos.
This commit is contained in:
parent
8d6c358ea8
commit
81147b5596
@ -83,7 +83,8 @@ typedef enum cudaVideoCodec_enum {
|
||||
* Video Surface Formats Enums
|
||||
*/
|
||||
typedef enum cudaVideoSurfaceFormat_enum {
|
||||
cudaVideoSurfaceFormat_NV12=0 /**< NV12 (currently the only supported output format) */
|
||||
cudaVideoSurfaceFormat_NV12=0, /**< NV12 */
|
||||
cudaVideoSurfaceFormat_P016=1 /**< P016 */
|
||||
} cudaVideoSurfaceFormat;
|
||||
|
||||
/*!
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
|
||||
#include "avcodec.h"
|
||||
#include "internal.h"
|
||||
@ -102,11 +103,46 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
|
||||
CuvidContext *ctx = avctx->priv_data;
|
||||
AVHWFramesContext *hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data;
|
||||
CUVIDDECODECREATEINFO cuinfo;
|
||||
int surface_fmt;
|
||||
|
||||
enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_CUDA,
|
||||
AV_PIX_FMT_NONE, // Will be updated below
|
||||
AV_PIX_FMT_NONE };
|
||||
|
||||
av_log(avctx, AV_LOG_TRACE, "pfnSequenceCallback, progressive_sequence=%d\n", format->progressive_sequence);
|
||||
|
||||
ctx->internal_error = 0;
|
||||
|
||||
switch (format->bit_depth_luma_minus8) {
|
||||
case 0: // 8-bit
|
||||
pix_fmts[1] = AV_PIX_FMT_NV12;
|
||||
break;
|
||||
case 2: // 10-bit
|
||||
pix_fmts[1] = AV_PIX_FMT_P010;
|
||||
break;
|
||||
case 4: // 12-bit
|
||||
pix_fmts[1] = AV_PIX_FMT_P016;
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
ctx->internal_error = AVERROR(EINVAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
av_log(avctx, AV_LOG_VERBOSE, "Formats: Original: %s | HW: %s | SW: %s\n",
|
||||
av_get_pix_fmt_name(avctx->pix_fmt),
|
||||
av_get_pix_fmt_name(surface_fmt),
|
||||
av_get_pix_fmt_name(avctx->sw_pix_fmt));
|
||||
|
||||
avctx->pix_fmt = surface_fmt;
|
||||
|
||||
avctx->width = format->display_area.right;
|
||||
avctx->height = format->display_area.bottom;
|
||||
|
||||
@ -155,7 +191,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
|
||||
hwframe_ctx->width < avctx->width ||
|
||||
hwframe_ctx->height < avctx->height ||
|
||||
hwframe_ctx->format != AV_PIX_FMT_CUDA ||
|
||||
hwframe_ctx->sw_format != AV_PIX_FMT_NV12)) {
|
||||
hwframe_ctx->sw_format != avctx->sw_pix_fmt)) {
|
||||
av_log(avctx, AV_LOG_ERROR, "AVHWFramesContext is already initialized with incompatible parameters\n");
|
||||
ctx->internal_error = AVERROR(EINVAL);
|
||||
return 0;
|
||||
@ -176,7 +212,20 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
|
||||
|
||||
cuinfo.CodecType = ctx->codec_type = format->codec;
|
||||
cuinfo.ChromaFormat = format->chroma_format;
|
||||
cuinfo.OutputFormat = cudaVideoSurfaceFormat_NV12;
|
||||
|
||||
switch (avctx->sw_pix_fmt) {
|
||||
case AV_PIX_FMT_NV12:
|
||||
cuinfo.OutputFormat = cudaVideoSurfaceFormat_NV12;
|
||||
break;
|
||||
case AV_PIX_FMT_P010:
|
||||
case AV_PIX_FMT_P016:
|
||||
cuinfo.OutputFormat = cudaVideoSurfaceFormat_P016;
|
||||
break;
|
||||
default:
|
||||
av_log(avctx, AV_LOG_ERROR, "Output formats other than NV12, P010 or P016 are not supported\n");
|
||||
ctx->internal_error = AVERROR(EINVAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cuinfo.ulWidth = avctx->coded_width;
|
||||
cuinfo.ulHeight = avctx->coded_height;
|
||||
@ -208,7 +257,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
|
||||
|
||||
if (!hwframe_ctx->pool) {
|
||||
hwframe_ctx->format = AV_PIX_FMT_CUDA;
|
||||
hwframe_ctx->sw_format = AV_PIX_FMT_NV12;
|
||||
hwframe_ctx->sw_format = avctx->sw_pix_fmt;
|
||||
hwframe_ctx->width = avctx->width;
|
||||
hwframe_ctx->height = avctx->height;
|
||||
|
||||
@ -416,7 +465,9 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
|
||||
offset += avctx->coded_height;
|
||||
}
|
||||
} else if (avctx->pix_fmt == AV_PIX_FMT_NV12) {
|
||||
} else if (avctx->pix_fmt == AV_PIX_FMT_NV12 ||
|
||||
avctx->pix_fmt == AV_PIX_FMT_P010 ||
|
||||
avctx->pix_fmt == AV_PIX_FMT_P016) {
|
||||
AVFrame *tmp_frame = av_frame_alloc();
|
||||
if (!tmp_frame) {
|
||||
av_log(avctx, AV_LOG_ERROR, "av_frame_alloc failed\n");
|
||||
@ -446,7 +497,6 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
av_frame_free(&tmp_frame);
|
||||
goto error;
|
||||
}
|
||||
|
||||
av_frame_free(&tmp_frame);
|
||||
} else {
|
||||
ret = AVERROR_BUG;
|
||||
@ -614,17 +664,6 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx)
|
||||
const AVBitStreamFilter *bsf;
|
||||
int ret = 0;
|
||||
|
||||
enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_CUDA,
|
||||
AV_PIX_FMT_NV12,
|
||||
AV_PIX_FMT_NONE };
|
||||
|
||||
ret = ff_get_format(avctx, pix_fmts);
|
||||
if (ret < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR, "ff_get_format failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
avctx->pix_fmt = ret;
|
||||
|
||||
ret = cuvid_load_functions(&ctx->cvdl);
|
||||
if (ret < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Failed loading nvcuvid.\n");
|
||||
@ -899,6 +938,8 @@ static const AVOption options[] = {
|
||||
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
|
||||
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \
|
||||
AV_PIX_FMT_NV12, \
|
||||
AV_PIX_FMT_P010, \
|
||||
AV_PIX_FMT_P016, \
|
||||
AV_PIX_FMT_NONE }, \
|
||||
};
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#define LIBAVCODEC_VERSION_MAJOR 57
|
||||
#define LIBAVCODEC_VERSION_MINOR 66
|
||||
#define LIBAVCODEC_VERSION_MICRO 106
|
||||
#define LIBAVCODEC_VERSION_MICRO 107
|
||||
|
||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||
LIBAVCODEC_VERSION_MINOR, \
|
||||
|
Loading…
Reference in New Issue
Block a user