Skip to content

Instantly share code, notes, and snippets.

@Ewoodss
Created June 18, 2024 08:24
Show Gist options
  • Save Ewoodss/0cae85164bb0c257b4f876f297a6e40b to your computer and use it in GitHub Desktop.
Save Ewoodss/0cae85164bb0c257b4f876f297a6e40b to your computer and use it in GitHub Desktop.
ffmpeg 6.0 patch nvmpi rtsp
diff --git a/configure b/configure
index e06faa4..8087aee 100755
--- a/configure
+++ b/configure
@@ -353,6 +353,7 @@ External library support:
--disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect]
--disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect]
--disable-videotoolbox disable VideoToolbox code [autodetect]
+ --enable-nvmpi enable nvmpi code
Toolchain options:
--arch=ARCH select architecture [$arch]
@@ -1913,6 +1914,7 @@ HWACCEL_LIBRARY_LIST="
mmal
omx
opencl
+ nvmpi
"
DOCUMENT_LIST="
@@ -3179,12 +3181,15 @@ h264_mediacodec_encoder_select="h264_metadata"
h264_mf_encoder_deps="mediafoundation"
h264_mmal_decoder_deps="mmal"
h264_nvenc_encoder_deps="nvenc"
+h264_nvmpi_encoder_deps="nvmpi"
h264_nvenc_encoder_select="atsc_a53"
h264_omx_encoder_deps="omx"
h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec"
h264_qsv_encoder_select="atsc_a53 qsvenc"
h264_rkmpp_decoder_deps="rkmpp"
h264_rkmpp_decoder_select="h264_mp4toannexb_bsf"
+h264_nvmpi_decoder_deps="nvmpi"
+h264_nvmpi_decoder_select="h264_mp4toannexb_bsf"
h264_vaapi_encoder_select="atsc_a53 cbs_h264 vaapi_encode"
h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m"
h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf"
@@ -3201,10 +3206,13 @@ hevc_mediacodec_encoder_select="hevc_metadata"
hevc_mf_encoder_deps="mediafoundation"
hevc_nvenc_encoder_deps="nvenc"
hevc_nvenc_encoder_select="atsc_a53"
+hevc_nvmpi_encoder_deps="nvmpi"
hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec"
hevc_qsv_encoder_select="hevcparse qsvenc"
hevc_rkmpp_decoder_deps="rkmpp"
hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf"
+hevc_nvmpi_decoder_deps="nvmpi"
+hevc_nvmpi_decoder_select="hevc_mp4toannexb_bsf"
hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC"
hevc_vaapi_encoder_select="atsc_a53 cbs_h265 vaapi_encode"
hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m"
@@ -3221,6 +3229,7 @@ mpeg1_cuvid_decoder_deps="cuvid"
mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m"
mpeg2_crystalhd_decoder_select="crystalhd"
mpeg2_cuvid_decoder_deps="cuvid"
+mpeg2_nvmpi_decoder_deps="nvmpi"
mpeg2_mmal_decoder_deps="mmal"
mpeg2_mediacodec_decoder_deps="mediacodec"
mpeg2_qsv_decoder_select="qsvdec"
@@ -3229,6 +3238,7 @@ mpeg2_vaapi_encoder_select="cbs_mpeg2 vaapi_encode"
mpeg2_v4l2m2m_decoder_deps="v4l2_m2m mpeg2_v4l2_m2m"
mpeg4_crystalhd_decoder_select="crystalhd"
mpeg4_cuvid_decoder_deps="cuvid"
+mpeg4_nvmpi_decoder_deps="nvmpi"
mpeg4_mediacodec_decoder_deps="mediacodec"
mpeg4_mmal_decoder_deps="mmal"
mpeg4_omx_encoder_deps="omx"
@@ -3241,6 +3251,7 @@ vc1_mmal_decoder_deps="mmal"
vc1_qsv_decoder_select="qsvdec"
vc1_v4l2m2m_decoder_deps="v4l2_m2m vc1_v4l2_m2m"
vp8_cuvid_decoder_deps="cuvid"
+vp8_nvmpi_decoder_deps="nvmpi"
vp8_mediacodec_decoder_deps="mediacodec"
vp8_qsv_decoder_select="qsvdec"
vp8_rkmpp_decoder_deps="rkmpp"
@@ -3249,6 +3260,7 @@ vp8_vaapi_encoder_select="vaapi_encode"
vp8_v4l2m2m_decoder_deps="v4l2_m2m vp8_v4l2_m2m"
vp8_v4l2m2m_encoder_deps="v4l2_m2m vp8_v4l2_m2m"
vp9_cuvid_decoder_deps="cuvid"
+vp9_nvmpi_decoder_deps="nvmpi"
vp9_mediacodec_decoder_deps="mediacodec"
vp9_qsv_decoder_select="qsvdec"
vp9_rkmpp_decoder_deps="rkmpp"
@@ -6807,6 +6819,7 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r
die "ERROR: rkmpp requires --enable-libdrm"; }
}
enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init
+enabled nvmpi && require_pkg_config nvmpi nvmpi nvmpi.h nvmpi_create_decoder
if enabled gcrypt; then
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 389253f..de624e0 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -409,6 +409,8 @@ OBJS-$(CONFIG_H264_MEDIACODEC_ENCODER) += mediacodecenc.o
OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o
OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o
+OBJS-$(CONFIG_H264_NVMPI_DECODER) += nvmpi_dec.o
+OBJS-$(CONFIG_H264_NVMPI_ENCODER) += nvmpi_enc.o
OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o
OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o
OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o
@@ -442,6 +444,8 @@ OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o h265_profile_level
h2645data.o
OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER) += v4l2_m2m_dec.o
OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER) += v4l2_m2m_enc.o
+OBJS-$(CONFIG_HEVC_NVMPI_DECODER) += nvmpi_dec.o
+OBJS-$(CONFIG_HEVC_NVMPI_ENCODER) += nvmpi_enc.o
OBJS-$(CONFIG_HEVC_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o
OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o
OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadata.o hq_hqadsp.o \
@@ -535,12 +539,14 @@ OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o
OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o
OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o
OBJS-$(CONFIG_MPEG2_CUVID_DECODER) += cuviddec.o
+OBJS-$(CONFIG_MPEG2_NVMPI_DECODER) += nvmpi_dec.o
OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER) += vaapi_encode_mpeg2.o
OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER) += v4l2_m2m_dec.o
OBJS-$(CONFIG_MPEG4_DECODER) += mpeg4videodsp.o xvididct.o
OBJS-$(CONFIG_MPEG4_ENCODER) += mpeg4videoenc.o
OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o
+OBJS-$(CONFIG_MPEG4_NVMPI_DECODER) += nvmpi_dec.o
OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_MPEG4_OMX_ENCODER) += omx.o
OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER) += v4l2_m2m_dec.o
@@ -763,6 +769,7 @@ OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o \
OBJS-$(CONFIG_VP7_DECODER) += vp8.o vpx_rac.o
OBJS-$(CONFIG_VP8_DECODER) += vp8.o vpx_rac.o
OBJS-$(CONFIG_VP8_CUVID_DECODER) += cuviddec.o
+OBJS-$(CONFIG_VP8_NVMPI_DECODER) += nvmpi_dec.o
OBJS-$(CONFIG_VP8_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_VP8_QSV_DECODER) += qsvdec.o
OBJS-$(CONFIG_VP8_RKMPP_DECODER) += rkmppdec.o
@@ -773,6 +780,7 @@ OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r
vp9block.o vp9prob.o vp9mvs.o vpx_rac.o \
vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o
OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuviddec.o
+OBJS-$(CONFIG_VP9_NVMPI_DECODER) += nvmpi_dec.o
OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_VP9_RKMPP_DECODER) += rkmppdec.o
OBJS-$(CONFIG_VP9_VAAPI_ENCODER) += vaapi_encode_vp9.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index e593ad1..954ed1b 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -158,11 +158,15 @@ extern const FFCodec ff_h264_mediacodec_encoder;
extern const FFCodec ff_h264_mmal_decoder;
extern const FFCodec ff_h264_qsv_decoder;
extern const FFCodec ff_h264_rkmpp_decoder;
+extern const FFCodec ff_h264_nvmpi_decoder;
+extern const FFCodec ff_h264_nvmpi_encoder;
extern const FFCodec ff_hap_encoder;
extern const FFCodec ff_hap_decoder;
extern const FFCodec ff_hevc_decoder;
extern const FFCodec ff_hevc_qsv_decoder;
extern const FFCodec ff_hevc_rkmpp_decoder;
+extern const FFCodec ff_hevc_nvmpi_decoder;
+extern const FFCodec ff_hevc_nvmpi_encoder;
extern const FFCodec ff_hevc_v4l2m2m_decoder;
extern const FFCodec ff_hnm4_video_decoder;
extern const FFCodec ff_hq_hqa_decoder;
@@ -867,20 +871,24 @@ extern const FFCodec ff_mjpeg_vaapi_encoder;
extern const FFCodec ff_mp3_mf_encoder;
extern const FFCodec ff_mpeg1_cuvid_decoder;
extern const FFCodec ff_mpeg2_cuvid_decoder;
+extern const FFCodec ff_mpeg2_nvmpi_decoder;
extern const FFCodec ff_mpeg2_qsv_encoder;
extern const FFCodec ff_mpeg2_vaapi_encoder;
extern const FFCodec ff_mpeg4_cuvid_decoder;
+extern const FFCodec ff_mpeg4_nvmpi_decoder;
extern const FFCodec ff_mpeg4_mediacodec_decoder;
extern const FFCodec ff_mpeg4_omx_encoder;
extern const FFCodec ff_mpeg4_v4l2m2m_encoder;
extern const FFCodec ff_prores_videotoolbox_encoder;
extern const FFCodec ff_vc1_cuvid_decoder;
extern const FFCodec ff_vp8_cuvid_decoder;
+extern const FFCodec ff_vp8_nvmpi_decoder;
extern const FFCodec ff_vp8_mediacodec_decoder;
extern const FFCodec ff_vp8_qsv_decoder;
extern const FFCodec ff_vp8_v4l2m2m_encoder;
extern const FFCodec ff_vp8_vaapi_encoder;
extern const FFCodec ff_vp9_cuvid_decoder;
+extern const FFCodec ff_vp9_nvmpi_decoder;
extern const FFCodec ff_vp9_mediacodec_decoder;
extern const FFCodec ff_vp9_qsv_decoder;
extern const FFCodec ff_vp9_vaapi_encoder;
diff --git a/libavcodec/nvmpi_dec.c b/libavcodec/nvmpi_dec.c
new file mode 100644
index 0000000..cf6ec79
--- /dev/null
+++ b/libavcodec/nvmpi_dec.c
@@ -0,0 +1,244 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <nvmpi.h>
+#include "avcodec.h"
+#include "decode.h"
+#include "internal.h"
+#include "libavutil/buffer.h"
+#include "libavutil/common.h"
+#include "libavutil/frame.h"
+#include "libavutil/hwcontext.h"
+#include "libavutil/hwcontext_drm.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+
+#if LIBAVCODEC_VERSION_MAJOR >= 60
+#include "codec_internal.h"
+#endif
+
+
+typedef struct {
+ char eos_reached;
+ nvmpictx* ctx;
+ AVClass *av_class;
+ AVFrame *bufFrame;
+ char *resize_expr;
+} nvmpiDecodeContext;
+
+static nvCodingType nvmpi_get_codingtype(AVCodecContext *avctx)
+{
+ switch (avctx->codec_id) {
+ case AV_CODEC_ID_H264: return NV_VIDEO_CodingH264;
+ case AV_CODEC_ID_HEVC: return NV_VIDEO_CodingHEVC;
+ case AV_CODEC_ID_VP8: return NV_VIDEO_CodingVP8;
+ case AV_CODEC_ID_VP9: return NV_VIDEO_CodingVP9;
+ case AV_CODEC_ID_MPEG4: return NV_VIDEO_CodingMPEG4;
+ case AV_CODEC_ID_MPEG2VIDEO: return NV_VIDEO_CodingMPEG2;
+ default: return NV_VIDEO_CodingUnused;
+ }
+};
+
+
+static int nvmpi_init_decoder(AVCodecContext *avctx){
+
+ nvmpiDecodeContext *nvmpi_context = avctx->priv_data;
+ nvCodingType codectype=NV_VIDEO_CodingUnused;
+ nvSize resized = {0};
+
+ codectype =nvmpi_get_codingtype(avctx);
+ if (codectype == NV_VIDEO_CodingUnused) {
+ av_log(avctx, AV_LOG_ERROR, "Unknown codec type (%d).\n", avctx->codec_id);
+ return AVERROR_UNKNOWN;
+ }
+
+ //Workaround for default pix_fmt not being set, so check if it isnt set and set it,
+ //or if it is set, but isnt set to something we can work with.
+
+ if(avctx->pix_fmt ==AV_PIX_FMT_NONE){
+ avctx->pix_fmt=AV_PIX_FMT_YUV420P;
+ }else if((avctx->pix_fmt != AV_PIX_FMT_YUV420P) && (avctx->pix_fmt != AV_PIX_FMT_YUVJ420P)){
+ av_log(avctx, AV_LOG_ERROR, "Invalid Pix_FMT for NVMPI: Only YUV420P and YUVJ420P are supported\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (nvmpi_context->resize_expr && sscanf(nvmpi_context->resize_expr, "%dx%d",
+ &resized.width, &resized.height) != 2) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid resize expressions\n");
+ return AVERROR(EINVAL);
+ }
+
+ //overwrite avctx w and h if resize option is used
+ if(resized.width && resized.height)
+ {
+ avctx->width = resized.width;
+ avctx->height = resized.height;
+ }
+
+ nvmpi_context->bufFrame = av_frame_alloc();
+ nvmpi_context->bufFrame->width = avctx->width;
+ nvmpi_context->bufFrame->height = avctx->height;
+ if (ff_get_buffer(avctx, nvmpi_context->bufFrame, 0) < 0) {
+ av_frame_free(&(nvmpi_context->bufFrame));
+ nvmpi_context->bufFrame = NULL;
+ return AVERROR(ENOMEM);
+ }
+
+ nvmpi_context->ctx=nvmpi_create_decoder(codectype, NV_PIX_YUV420, resized);
+
+ if(!nvmpi_context->ctx){
+ av_frame_free(&(nvmpi_context->bufFrame));
+ nvmpi_context->bufFrame = NULL;
+ av_log(avctx, AV_LOG_ERROR, "Failed to nvmpi_create_decoder (code = %d).\n", AVERROR_EXTERNAL);
+ return AVERROR_EXTERNAL;
+ }
+
+ // AVCodecContext extradata contains complete NALU with pps, just have to feed it to the decoder
+ if(avctx->extradata_size){
+ nvPacket packet;
+ int r;
+
+ packet.payload_size=avctx->extradata_size;
+ packet.payload=avctx->extradata;
+ packet.pts=0;
+
+ r = nvmpi_decoder_put_packet(nvmpi_context->ctx,&packet);
+ if (r < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to put pps packet (code = %d).\n", r);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+
+
+static int nvmpi_close(AVCodecContext *avctx){
+
+ nvmpiDecodeContext *nvmpi_context = avctx->priv_data;
+ if(nvmpi_context->bufFrame)
+ {
+ av_frame_free(&(nvmpi_context->bufFrame));
+ nvmpi_context->bufFrame = NULL;
+ }
+ return nvmpi_decoder_close(nvmpi_context->ctx);
+
+}
+
+#if LIBAVCODEC_VERSION_MAJOR >= 60
+static int nvmpi_decode(AVCodecContext *avctx,AVFrame *data,int *got_frame, AVPacket *avpkt)
+#else
+static int nvmpi_decode(AVCodecContext *avctx,void *data,int *got_frame, AVPacket *avpkt)
+#endif
+{
+ nvmpiDecodeContext *nvmpi_context = avctx->priv_data;
+ AVFrame *frame = data;
+ AVFrame *bufFrame = nvmpi_context->bufFrame;
+ nvFrame _nvframe={0};
+ nvPacket packet;
+ int res;
+
+ if(avpkt->size){
+ packet.payload_size=avpkt->size;
+ packet.payload=avpkt->data;
+ packet.pts=avpkt->pts;
+
+ res=nvmpi_decoder_put_packet(nvmpi_context->ctx,&packet);
+ }
+
+ _nvframe.payload[0] = bufFrame->data[0];
+ _nvframe.payload[1] = bufFrame->data[1];
+ _nvframe.payload[2] = bufFrame->data[2];
+ _nvframe.linesize[0] = bufFrame->linesize[0];
+ _nvframe.linesize[1] = bufFrame->linesize[1];
+ _nvframe.linesize[2] = bufFrame->linesize[2];
+
+ res=nvmpi_decoder_get_frame(nvmpi_context->ctx,&_nvframe,avctx->flags & AV_CODEC_FLAG_LOW_DELAY);
+
+ if(res<0)
+ return avpkt->size;
+
+ bufFrame->format=AV_PIX_FMT_YUV420P;
+ bufFrame->pts=_nvframe.timestamp;
+ bufFrame->pkt_dts = AV_NOPTS_VALUE;
+ av_frame_move_ref(frame, bufFrame);
+
+ *got_frame = 1;
+
+ bufFrame->width = avctx->width;
+ bufFrame->height = avctx->height;
+ if (ff_get_buffer(avctx, bufFrame, 0) < 0) {
+ return AVERROR(ENOMEM);
+ }
+
+ frame->metadata = bufFrame->metadata;
+ bufFrame->metadata = NULL;
+
+ return avpkt->size;
+}
+
+
+
+#define OFFSET(x) offsetof(nvmpiDecodeContext, x)
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "resize", "Resize (width)x(height)", OFFSET(resize_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
+ { NULL }
+};
+
+#define NVMPI_DEC_CLASS(NAME) \
+ static const AVClass nvmpi_##NAME##_dec_class = { \
+ .class_name = "nvmpi_" #NAME "_dec", \
+ .option = options, \
+ .version = LIBAVUTIL_VERSION_INT, \
+ };
+
+#if LIBAVCODEC_VERSION_MAJOR >= 60
+ #define NVMPI_DEC(NAME, ID, BSFS) \
+ NVMPI_DEC_CLASS(NAME) \
+ FFCodec ff_##NAME##_nvmpi_decoder = { \
+ .p.name = #NAME "_nvmpi", \
+ CODEC_LONG_NAME(#NAME " (nvmpi)"), \
+ .p.type = AVMEDIA_TYPE_VIDEO, \
+ .p.id = ID, \
+ .priv_data_size = sizeof(nvmpiDecodeContext), \
+ .init = nvmpi_init_decoder, \
+ .close = nvmpi_close, \
+ FF_CODEC_DECODE_CB(nvmpi_decode), \
+ .p.priv_class = &nvmpi_##NAME##_dec_class, \
+ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
+ .p.pix_fmts =(const enum AVPixelFormat[]){AV_PIX_FMT_YUV420P,AV_PIX_FMT_NV12,AV_PIX_FMT_NONE},\
+ .bsfs = BSFS, \
+ .p.wrapper_name = "nvmpi", \
+ };
+#else
+ #define NVMPI_DEC(NAME, ID, BSFS) \
+ NVMPI_DEC_CLASS(NAME) \
+ AVCodec ff_##NAME##_nvmpi_decoder = { \
+ .name = #NAME "_nvmpi", \
+ .long_name = NULL_IF_CONFIG_SMALL(#NAME " (nvmpi)"), \
+ .type = AVMEDIA_TYPE_VIDEO, \
+ .id = ID, \
+ .priv_data_size = sizeof(nvmpiDecodeContext), \
+ .init = nvmpi_init_decoder, \
+ .close = nvmpi_close, \
+ .decode = nvmpi_decode, \
+ .priv_class = &nvmpi_##NAME##_dec_class, \
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
+ .pix_fmts =(const enum AVPixelFormat[]){AV_PIX_FMT_YUV420P,AV_PIX_FMT_NV12,AV_PIX_FMT_NONE},\
+ .bsfs = BSFS, \
+ .wrapper_name = "nvmpi", \
+ };
+#endif
+
+
+NVMPI_DEC(h264, AV_CODEC_ID_H264,"h264_mp4toannexb");
+NVMPI_DEC(hevc, AV_CODEC_ID_HEVC,"hevc_mp4toannexb");
+NVMPI_DEC(mpeg2, AV_CODEC_ID_MPEG2VIDEO,NULL);
+NVMPI_DEC(mpeg4, AV_CODEC_ID_MPEG4,NULL);
+NVMPI_DEC(vp9, AV_CODEC_ID_VP9,NULL);
+NVMPI_DEC(vp8, AV_CODEC_ID_VP8,NULL);
+
diff --git a/libavcodec/nvmpi_enc.c b/libavcodec/nvmpi_enc.c
new file mode 100644
index 0000000..957b7e0
--- /dev/null
+++ b/libavcodec/nvmpi_enc.c
@@ -0,0 +1,557 @@
+#include <nvmpi.h>
+#include "avcodec.h"
+#include "internal.h"
+#include <stdio.h>
+#include "libavutil/avstring.h"
+#include "libavutil/avutil.h"
+#include "libavutil/common.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+
+#include "version.h"
+
+#if (LIBAVCODEC_VERSION_MAJOR >= 58 && LIBAVCODEC_VERSION_MINOR>= 134) || (LIBAVCODEC_VERSION_MAJOR >= 59)
+#define NVMPI_FF_NEW_API
+#include "encode.h"
+#endif
+#if (LIBAVCODEC_VERSION_MAJOR >= 60)
+#include "codec_internal.h"
+#endif
+
+
+typedef struct {
+ const AVClass *class;
+ nvmpictx* ctx;
+ int num_capture_buffers;
+ int profile;
+ int level;
+ int rc;
+ int preset;
+ int encoder_flushing;
+ AVFrame *frame; //tmp frame
+}nvmpiEncodeContext;
+
+nvPacket* nvmpienc_nvPacket_alloc(AVCodecContext *avctx, int bufSize);
+void nvmpienc_nvPacket_free(nvPacket* nPkt);
+int nvmpienc_nvPacket_reset(nvPacket* nPkt, AVCodecContext *avctx, int bufSize);
+int nvmpienc_initPktPool(AVCodecContext *avctx, int pktNum);
+int nvmpienc_deinitPktPool(AVCodecContext *avctx);
+
+//alloc nvPacket and AVPacket buffer;
+nvPacket* nvmpienc_nvPacket_alloc(AVCodecContext *avctx, int bufSize)
+{
+ AVPacket* pkt = av_packet_alloc();
+ nvPacket* nPkt = (nvPacket*)malloc(sizeof(nvPacket));
+ int res;
+ memset(nPkt, 0, sizeof(nvPacket));
+#if LIBAVCODEC_VERSION_MAJOR >= 60
+ if((res = ff_get_encode_buffer(avctx, pkt, bufSize, 0)))
+#else
+ if((res = ff_alloc_packet2(avctx,pkt,bufSize,bufSize)))
+#endif
+ {
+ av_packet_free(&pkt);
+ free(nPkt);
+ return NULL;
+ }
+ nPkt->privData = pkt;
+ nPkt->payload = pkt->data;
+ return nPkt;
+}
+
+void nvmpienc_nvPacket_free(nvPacket* nPkt)
+{
+ AVPacket* pkt = nPkt->privData;
+ av_packet_free(&pkt);
+ free(nPkt);
+}
+
+int nvmpienc_nvPacket_reset(nvPacket* nPkt, AVCodecContext *avctx, int bufSize)
+{
+ AVPacket* pkt = nPkt->privData;
+ int res;
+#if LIBAVCODEC_VERSION_MAJOR >= 60
+ if((res = ff_get_encode_buffer(avctx, pkt, bufSize, 0)))
+#else
+ if((res = ff_alloc_packet2(avctx,pkt,bufSize,bufSize)))
+#endif
+ {
+ return -1;
+ }
+ nPkt->payload = pkt->data;
+ nPkt->payload_size = 0;
+ nPkt->flags = 0;
+ nPkt->pts = 0;
+ return 0;
+}
+
+//must call after nvmpi_create_encoder() to preallocate buffers
+int nvmpienc_initPktPool(AVCodecContext *avctx, int pktNum)
+{
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data;
+ //TODO free allocated mem on error
+ for(int i=0;i<pktNum;i++)
+ {
+ nvPacket* nPkt = nvmpienc_nvPacket_alloc(avctx, NVMPI_ENC_CHUNK_SIZE);
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt);
+ }
+ return 0;
+}
+
+//must call before nvmpi_encoder_close() too free buffers memory
+int nvmpienc_deinitPktPool(AVCodecContext *avctx)
+{
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data;
+ nvmpictx *ctx = nvmpi_context->ctx;
+ nvPacket* nPkt;
+
+ while(nvmpi_encoder_dqEmptyPacket(ctx, &nPkt) == 0)
+ {
+ AVPacket* pkt = nPkt->privData;
+ av_packet_free(&pkt);
+ free(nPkt);
+ }
+ while(nvmpi_encoder_get_packet(ctx, &nPkt) == 0)
+ {
+ AVPacket* pkt = nPkt->privData;
+ av_packet_free(&pkt);
+ free(nPkt);
+ }
+
+ //TODO check that all mem returned to nothing
+ return 0;
+}
+
+static av_cold int nvmpi_encode_init(AVCodecContext *avctx)
+{
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data;
+
+ nvEncParam param={0};
+
+ param.width=avctx->width;
+ param.height=avctx->height;
+ param.bitrate=avctx->bit_rate;
+ param.vbv_buffer_size = avctx->rc_buffer_size;
+ //TODO use rc_initial_buffer_occupancy or ignore?
+ param.mode_vbr=0;
+ param.idr_interval=60;
+ param.iframe_interval=30;
+ param.peak_bitrate=avctx->rc_max_rate;
+ param.fps_n=avctx->framerate.num;
+ param.fps_d=avctx->framerate.den;
+ param.profile=nvmpi_context->profile& ~FF_PROFILE_H264_INTRA;
+ param.level=nvmpi_context->level;
+ param.capture_num=nvmpi_context->num_capture_buffers;
+ param.hw_preset_type=nvmpi_context->preset;
+ param.insert_spspps_idr=(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)?0:1;
+
+ nvmpi_context->frame = av_frame_alloc();
+ if (!nvmpi_context->frame) return AVERROR(ENOMEM);
+
+ if(nvmpi_context->rc==1){
+ param.mode_vbr=1;
+ }
+
+ if(avctx->qmin >= 0 && avctx->qmax >= 0){
+ param.qmin=avctx->qmin;
+ param.qmax=avctx->qmax;
+ }
+
+ if (avctx->refs >= 0){
+ param.refs=avctx->refs;
+
+ }
+
+ if(avctx->max_b_frames > 0 && avctx->max_b_frames < 3){
+ param.max_b_frames=avctx->max_b_frames;
+ }
+
+ if(avctx->gop_size>0){
+ param.idr_interval=param.iframe_interval=avctx->gop_size;
+
+ }
+
+ //TODO should replace it
+ if ((avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) && (avctx->codec->id == AV_CODEC_ID_H264)){
+
+ uint8_t *dst[4];
+ int linesize[4];
+ nvFrame _nvframe={0};
+ nvPacket *nPkt;
+ nvmpictx *_ctx;
+ int i;
+ int ret;
+ av_image_alloc(dst, linesize,avctx->width,avctx->height,avctx->pix_fmt,1);
+
+ nvmpi_context->ctx = nvmpi_create_encoder(NV_VIDEO_CodingH264,&param);
+ _ctx = nvmpi_context->ctx;
+ //TODO error handling. if(!_ctx)
+ nvmpienc_initPktPool(avctx,nvmpi_context->num_capture_buffers);
+ i=0;
+
+ while(true)
+ {
+ _nvframe.payload[0]=dst[0];
+ _nvframe.payload[1]=dst[1];
+ _nvframe.payload[2]=dst[2];
+ _nvframe.payload_size[0]=linesize[0]*avctx->height;
+ _nvframe.payload_size[1]=linesize[1]*avctx->height/2;
+ _nvframe.payload_size[2]=linesize[2]*avctx->height/2;
+
+ nvmpi_encoder_put_frame(_ctx,&_nvframe);
+
+ ret=nvmpi_encoder_get_packet(_ctx,&nPkt);
+
+ if(ret<0)
+ continue;
+
+ //find idr index 0x0000000165
+ while((nPkt->payload[i]!=0||nPkt->payload[i+1]!=0||nPkt->payload[i+2]!=0||nPkt->payload[i+3]!=0x01||nPkt->payload[i+4]!=0x65))
+ {
+ i++;
+ }
+
+ avctx->extradata_size=i;
+ avctx->extradata = av_mallocz( avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE );
+ memcpy( avctx->extradata, nPkt->payload,avctx->extradata_size);
+ memset( avctx->extradata + avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE );
+
+ nvmpienc_nvPacket_free(nPkt);
+ nPkt = nvmpienc_nvPacket_alloc(avctx, NVMPI_ENC_CHUNK_SIZE);
+
+ //return buffer to pool
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt);
+ //send eos
+ nvmpi_encoder_put_frame(nvmpi_context->ctx,NULL);
+
+ break;
+ }
+
+ //drain encoder
+ while(true)
+ {
+ ret=nvmpi_encoder_get_packet(_ctx,&nPkt);
+ if(ret < 0)
+ {
+ if(ret == -2) break; //got eos
+ usleep(1000);
+ continue;
+ }
+ nvmpienc_nvPacket_free(nPkt);
+ nPkt = nvmpienc_nvPacket_alloc(avctx, NVMPI_ENC_CHUNK_SIZE);
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt);
+ }
+
+ av_freep(&dst[0]); //free allocated image planes
+ nvmpienc_deinitPktPool(avctx);
+ nvmpi_encoder_close(nvmpi_context->ctx);
+ nvmpi_context->ctx = NULL;
+ }
+
+ if(avctx->codec->id == AV_CODEC_ID_H264)
+ {
+ nvmpi_context->ctx=nvmpi_create_encoder(NV_VIDEO_CodingH264,&param);
+ }
+ else if(avctx->codec->id == AV_CODEC_ID_HEVC)
+ {
+ nvmpi_context->ctx=nvmpi_create_encoder(NV_VIDEO_CodingHEVC,&param);
+ }
+ //else TODO
+
+ if(nvmpi_context->ctx)
+ {
+ nvmpienc_initPktPool(avctx,nvmpi_context->num_capture_buffers);
+ }
+ //TODO error handling. if(!nvmpi_context->ctx)
+
+ return 0;
+}
+
+static int ff_nvmpi_send_frame(AVCodecContext *avctx,const AVFrame *frame)
+{
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data;
+ nvFrame _nvframe={0};
+ int res;
+
+ if (nvmpi_context->encoder_flushing)
+ return AVERROR_EOF;
+
+ if(frame)
+ {
+ _nvframe.payload[0]=frame->data[0];
+ _nvframe.payload[1]=frame->data[1];
+ _nvframe.payload[2]=frame->data[2];
+
+ _nvframe.payload_size[0]=frame->linesize[0]*frame->height;
+ _nvframe.payload_size[1]=frame->linesize[1]*frame->height/2;
+ _nvframe.payload_size[2]=frame->linesize[2]*frame->height/2;
+
+ _nvframe.linesize[0]=frame->linesize[0];
+ _nvframe.linesize[1]=frame->linesize[1];
+ _nvframe.linesize[2]=frame->linesize[2];
+
+ _nvframe.timestamp=frame->pts;
+
+ res=nvmpi_encoder_put_frame(nvmpi_context->ctx,&_nvframe);
+
+ if(res<0)
+ return res;
+ }
+ else
+ {
+ nvmpi_context->encoder_flushing = 1;
+ nvmpi_encoder_put_frame(nvmpi_context->ctx,NULL);
+ }
+
+ return 0;
+}
+
+static int ff_nvmpi_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
+{
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data;
+ nvPacket *nPkt;
+ AVPacket *aPkt;
+ int res;
+
+ res = nvmpi_encoder_get_packet(nvmpi_context->ctx,&nPkt);
+ if(res<0)
+ {
+ //If the encoder is in flushing state, then get_packet will block and return either a packet or EOF
+ if(nvmpi_context->encoder_flushing) return AVERROR_EOF;
+ return AVERROR(EAGAIN); //nvmpi get_packet returns -1 if no packets are pending
+ }
+
+ aPkt = (AVPacket*)(nPkt->privData);
+ aPkt->dts=aPkt->pts=nPkt->pts;
+ av_shrink_packet(aPkt, nPkt->payload_size);
+ if(nPkt->flags& AV_PKT_FLAG_KEY) aPkt->flags = AV_PKT_FLAG_KEY;
+ av_packet_move_ref(pkt, aPkt);
+
+ if(nvmpienc_nvPacket_reset(nPkt, avctx, NVMPI_ENC_CHUNK_SIZE))
+ {
+ nvmpienc_nvPacket_free(nPkt);
+ return AVERROR(ENOMEM);
+ }
+
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt);
+
+ return 0;
+}
+
+/*
+ * //old avcodec .encode2 api. TODO: remove it
+static int ff_nvmpi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,const AVFrame *frame, int *got_packet)
+{
+ int res;
+ *got_packet = 0;
+
+ res = ff_nvmpi_send_frame(avctx, frame);
+
+ if(res < 0)
+ {
+ if(res != AVERROR_EOF && res != AVERROR(EAGAIN)) return res;
+ }
+
+ res = ff_nvmpi_receive_packet(avctx, pkt);
+ if(res<0) return res;
+
+ *got_packet = 1;
+
+ return 0;
+}
+*/
+
+#ifdef NVMPI_FF_NEW_API
+static int ff_nvmpi_receive_packet_async(AVCodecContext *avctx, AVPacket *pkt)
+{
+ int res;
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data;
+ AVFrame *frame = nvmpi_context->frame;
+ bool needSendFrame = true;
+
+ if (!frame->buf[0])
+ {
+ res = ff_encode_get_frame(avctx, frame);
+ if (res < 0)
+ {
+ if(res == AVERROR(EAGAIN)) needSendFrame = false;
+ else if(res == AVERROR_EOF) frame = NULL;
+ else return res;
+ }
+ }
+
+ if(needSendFrame)
+ {
+ res = ff_nvmpi_send_frame(avctx, frame);
+ if (res < 0)
+ {
+ if(res != AVERROR_EOF && res != AVERROR(EAGAIN)) return res;
+ }
+ else av_frame_unref(frame);
+ }
+
+ res = ff_nvmpi_receive_packet(avctx, pkt);
+ if(res<0) return res;
+
+ return 0;
+}
+#endif
+
+static av_cold int nvmpi_encode_close(AVCodecContext *avctx)
+{
+ nvmpiEncodeContext *nvmpi_context = avctx->priv_data;
+
+ //drain encoder
+ {
+ int ret;
+ nvPacket *nPkt;
+ if(!nvmpi_context->encoder_flushing)
+ {
+ nvmpi_context->encoder_flushing = 1;
+ nvmpi_encoder_put_frame(nvmpi_context->ctx,NULL);
+ }
+
+ while(1)
+ {
+ ret=nvmpi_encoder_get_packet(nvmpi_context->ctx,&nPkt);
+ if(ret < 0)
+ {
+ if(ret == -2) break; //got eos
+ usleep(1000);
+ continue;
+ }
+ nvmpienc_nvPacket_free(nPkt);
+ nPkt = nvmpienc_nvPacket_alloc(avctx, NVMPI_ENC_CHUNK_SIZE);
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt);
+ }
+ }
+
+ nvmpienc_deinitPktPool(avctx);
+ nvmpi_encoder_close(nvmpi_context->ctx);
+ av_frame_free(&nvmpi_context->frame);
+
+ return 0;
+}
+
+#if LIBAVCODEC_VERSION_MAJOR >= 60
+static const FFCodecDefault defaults[] = {
+#else
+static const AVCodecDefault defaults[] = {
+#endif
+ { "b", "2M" },
+ { "qmin", "-1" },
+ { "qmax", "-1" },
+ { "qdiff", "-1" },
+ { "qblur", "-1" },
+ { "qcomp", "-1" },
+ { "g", "50" },
+ { "bf", "0" },
+ { "refs", "0" },
+ { NULL },
+};
+
+
+#define OFFSET(x) offsetof(nvmpiEncodeContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+
+static const AVOption options[] = {
+ { "num_capture_buffers", "Number of buffers in the capture context", OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 10 }, 1, 32, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
+ /// Profile,
+
+ { "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, FF_PROFILE_H264_HIGH, VE, "profile" },
+ { "baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_BASELINE }, 0, 0, VE, "profile" },
+ { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_MAIN }, 0, 0, VE, "profile" },
+ { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_HIGH }, 0, 0, VE, "profile" },
+
+ /// Profile Level
+ { "level", "Profile Level", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 62, VE, "level" },
+ { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "level" },
+ { "1.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 10 }, 0, 0, VE, "level" },
+ { "1.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 11 }, 0, 0, VE, "level" },
+ { "1.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 12 }, 0, 0, VE, "level" },
+ { "1.3", "", 0, AV_OPT_TYPE_CONST, { .i64 = 13 }, 0, 0, VE, "level" },
+ { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 20 }, 0, 0, VE, "level" },
+ { "2.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 21 }, 0, 0, VE, "level" },
+ { "2.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 22 }, 0, 0, VE, "level" },
+ { "3.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 30 }, 0, 0, VE, "level" },
+ { "3.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 31 }, 0, 0, VE, "level" },
+ { "3.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 32 }, 0, 0, VE, "level" },
+ { "4.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 40 }, 0, 0, VE, "level" },
+ { "4.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 41 }, 0, 0, VE, "level" },
+ { "4.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 42 }, 0, 0, VE, "level" },
+ { "5.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 50 }, 0, 0, VE, "level" },
+ { "5.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, 0, 0, VE, "level" },
+
+ { "rc", "Override the preset rate-control", OFFSET(rc), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, "rc" },
+ { "cbr", "Constant bitrate mode", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "rc" },
+ { "vbr", "Variable bitrate mode", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "rc" },
+
+ { "preset", "Set the encoding preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = 3 }, 1, 4, VE, "preset" },
+ { "default", "", 0, AV_OPT_TYPE_CONST, { .i64 = 3 }, 0, 0, VE, "preset" },
+ { "slow", "", 0, AV_OPT_TYPE_CONST, { .i64 = 4 }, 0, 0, VE, "preset" },
+ { "medium", "", 0, AV_OPT_TYPE_CONST, { .i64 = 3 }, 0, 0, VE, "preset" },
+ { "fast", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, VE, "preset" },
+ { "ultrafast", "", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "preset" },
+ { NULL }
+};
+
+
+#define NVMPI_ENC_CLASS(NAME) \
+ static const AVClass nvmpi_ ## NAME ## _enc_class = { \
+ .class_name = #NAME "_nvmpi_encoder", \
+ .item_name = av_default_item_name, \
+ .option = options, \
+ .version = LIBAVUTIL_VERSION_INT, \
+ };
+
+
+#if LIBAVCODEC_VERSION_MAJOR >= 60
+ #define NVMPI_ENC(NAME, LONGNAME, CODEC) \
+ NVMPI_ENC_CLASS(NAME) \
+ FFCodec ff_ ## NAME ## _nvmpi_encoder = { \
+ .p.name = #NAME "_nvmpi" , \
+ CODEC_LONG_NAME("nvmpi " LONGNAME " encoder wrapper"), \
+ .p.type = AVMEDIA_TYPE_VIDEO, \
+ .p.id = CODEC , \
+ .priv_data_size = sizeof(nvmpiEncodeContext), \
+ .p.priv_class = &nvmpi_ ## NAME ##_enc_class, \
+ .init = nvmpi_encode_init, \
+ FF_CODEC_RECEIVE_PACKET_CB(ff_nvmpi_receive_packet_async), \
+ .close = nvmpi_encode_close, \
+ .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },\
+ .p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \
+ .defaults = defaults,\
+ .p.wrapper_name = "nvmpi", \
+ };
+#else
+ #ifdef NVMPI_FF_NEW_API
+ #define NVMPI_ENC_API_CALLS \
+ .receive_packet = ff_nvmpi_receive_packet_async
+ #else
+ #define NVMPI_ENC_API_CALLS \
+ .send_frame = ff_nvmpi_send_frame, \
+ .receive_packet = ff_nvmpi_receive_packet
+ #endif
+
+ #define NVMPI_ENC(NAME, LONGNAME, CODEC) \
+ NVMPI_ENC_CLASS(NAME) \
+ AVCodec ff_ ## NAME ## _nvmpi_encoder = { \
+ .name = #NAME "_nvmpi" , \
+ .long_name = NULL_IF_CONFIG_SMALL("nvmpi " LONGNAME " encoder wrapper"), \
+ .type = AVMEDIA_TYPE_VIDEO, \
+ .id = CODEC , \
+ .priv_data_size = sizeof(nvmpiEncodeContext), \
+ .priv_class = &nvmpi_ ## NAME ##_enc_class, \
+ .init = nvmpi_encode_init, \
+ NVMPI_ENC_API_CALLS, \
+ .close = nvmpi_encode_close, \
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },\
+ .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \
+ .defaults = defaults,\
+ .wrapper_name = "nvmpi", \
+ };
+#endif
+
+NVMPI_ENC(h264, "H.264", AV_CODEC_ID_H264);
+NVMPI_ENC(hevc, "HEVC", AV_CODEC_ID_HEVC);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment